HDU - 4370 0 or 1 思维,最短路
给定n * n矩阵C ij(1 <= i,j <= n),我们要找到0或1的n * n矩阵X ij(1 <= i,j <= n)。 此外,X ij满足以下条件: 1.X 12 + X 13 + ... X 1n = 1 2.X 1n + X 2n + ... X n-1n = 1 3.对于每个i(1 <i <n),满足ΣXki(1 <= k <= n)=ΣXij(1 <= j <= n)。 例如,如果n = 4,我们可以得到以下等式: X 12 + X 13 + X 14 = 1 X 14 + X 24 + X 34 = 1 X 12 + X 22 + X 32 + X 42 = X 21 + X 22 + X 23 + X 24 X 13 + X 23 + X 33 + X 43 = X 31 + X 32 + X 33 + X 34 现在,我们想知道你可以得到的最小ΣCij * X ij(1 <= i,j <= n)。
给定的性质可以想到以下等价变化:
将xij转化为ij图的邻接矩阵。
1号点在2-n中有一个为1,其余0,相当于出度为1,n号点同理,入度为1 。其余点随意。
和C对应相乘相当于在C上找一条路径使得路径和最小。这样就转化成了最短路。
考虑最短路满足的条件 1.1-n的最短路 2.1到1的一个环,n到n的一个环,两者的叠加。
对于后者,只需要for一遍所有节点用已知的最短路维护即可,
int n, m;//n点数 m边数 struct edge { int v, w; edge(int a, int b) { v = a, w = b; } };//v终点,w边权 struct node { int id, dis;//id点编号 dis暂时距离 node(int a, int b) { id = a, dis = b; } friend bool operator<(node a, node b) { return a.dis > b.dis;//每次让距离小出队 } }; vector<edge>e[maxn]; int dis[maxn];//记录最短路 bool done[maxn];//记录是否找到最短路 int Min1, Min2; void dijkstra(int t) { int s = t;//s起点 根据情况改 for (int i = 0; i <= n; i++) dis[i] = INF, done[i] = 0; dis[s] = 0; priority_queue<node>Q; Q.push(node(s, 0)); while (!Q.empty()) { node u = Q.top(); Q.pop(); if (done[u.id])continue; done[u.id] = 1; for (int i = 0; i < e[u.id].size(); i++) {//遍历邻居 edge y = e[u.id][i]; if (done[y.v])continue; if (dis[y.v] > y.w + dis[u.id]) { dis[y.v] = y.w + u.dis; Q.push(node(y.v, dis[y.v]));//更新最短路 } } } if (t == 0) { for (int i = 0; i < n; i++) { if (i == t) continue; Min1 = min(Min1, dis[i] + e[i][t].w); } } else { for (int i = 0; i < n; i++) { if (i == t) continue; Min2 = min(Min2, dis[i] + e[i][t].w); } } } int main() { int res; int x; while (~scanf("%d", &n)) { Min1 = Min2 = INF; memset(e, 0, sizeof e); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) x = readint(), e[i].push_back(edge(j, x)); } for (int i = 0; i < n; i++) e[i][i].w = INF; dijkstra(0); res = dis[n - 1]; dijkstra(n - 1); printf("%d", min(res, (Min1 + Min2))); puts(""); } }