题意:给你一个矩阵C,让你构造一个只有01的矩阵X使 ∑C[i][j]*X [i][j](1<=i,j<=n) 最小,输出这个最小值。
构造出来得X矩阵需要满足一下关系:
1.X 12+X 13+...X 1n=1
2.X 1n+X 2n+...X n-1n=1
3.for each i (1<i<n), satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n)。
思路:超级难想的转化,其实对于这三个条件我们可以把理解为一下三个条件:
1.1点出度为1
2.n点的入度为1
3.其他点的出度入度相等。
那么问题就转化了,其实就是让我们求一条到1~N的最短路。但是会漏掉一种情况,1的最小环花费+n的最小环花费,且不能是自环(1,1和n,n点没有在1,2条件中),因为只规定了1点的出度为1,n点的入度为1。没规定1点的入度和n点的出度,所以min(1~N的最短路,1的最小环花费+n的最小环花费)就是答案。
这样就可以直接建图了,因为给的矩阵就相当于邻接矩阵。最短路好求,但是怎么求最小环花费呢。
我采取的方法是在求最短路的时候,立flag来进行计算,初始化flag=0,表示此时还没有1的环,即我之前没有碰到过一条u(!=s)~v(=s)的的边(即该边起点U不为S但终点V等于S)。如果碰到了,此时我们把d[s]更新且使flag=1表示已经有1的环了,以后再碰到这样的边两个环花费取较小值即可。
在我代码中也就是这两句话:
if (u != s && e.to == s && flag) d[s] = min(d[s], d[e.from] + e.dist);//之前碰见过了,两种环取一个环花费较小的
if (u != s && e.to == s && !flag) { flag = true; d[s] = d[e.from] + e.dist; }//第一次碰见终点为s的边且不是自环,那么直接赋值。
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
const int INF = 0x3f3f3f3f;
struct Edge
{
int from, to, dist;
Edge(int u, int v, int w): from(u), to(v), dist(w) {}
};
struct Dijkstra
{
int n, m;
vector<Edge> edges;
vector<int> G[MAXN];
int d[MAXN];
bool vis[MAXN];
int pre[MAXN];
void init(int n)
{
this->n = n;
edges.clear();
for (int i = 0; i <= n; i++) G[i].clear();
}
void add_edge(int from, int to, int dist)
{
edges.push_back(Edge(from, to, dist));
m = edges.size();
G[from].push_back(m - 1);
}
struct HeapNode
{
int from, dist;
bool operator < (const HeapNode& rhs) const
{
return rhs.dist < dist;
}
HeapNode(int u, int w): from(u), dist(w) {}
};
void dijkstra(int s)
{
for (int i = 0; i <= n; i++) d[i] = INF;
memset(vis, 0, sizeof(vis));
bool flag = false;//更新最小环用
d[s] = 0;
priority_queue<HeapNode> Q;
Q.push(HeapNode(s, d[s]));
while (!Q.empty())
{
HeapNode x = Q.top(); Q.pop();
int u = x.from;
if (vis[u]) continue;
vis[u] = true;
for (int i = 0; i < G[u].size(); i++)
{
Edge& e = edges[G[u][i]];
if (u != s && e.to == s && flag) d[s] = min(d[s], d[e.from] + e.dist);
if (u != s && e.to == s && !flag) { flag = true; d[s] = d[e.from] + e.dist; }
if (!vis[e.to] && d[e.to] > d[u] + e.dist)
{
d[e.to] = d[u] + e.dist;
pre[e.to] = G[u][i];
Q.push(HeapNode(e.to, d[e.to]));
}
}
}
}
};
Dijkstra solve;
int main()
{
int n;
while (~scanf("%d", &n))
{
solve.init(n);
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
int t; scanf("%d", &t);
solve.add_edge(i, j, t);
}
}
solve.dijkstra(1);
int ans = solve.d[n], loop1 = solve.d[1];
solve.dijkstra(n);
int loopn = solve.d[n];
ans = min(ans, loop1 + loopn);//1~n的最短路和(1的最小环花费 + n的最小环花费)
printf("%d\n", ans);
}
return 0;
}
/*
4
1 2 4 10
2 0 1 1
2 2 0 5
6 3 1 2
*/