题意: 给定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看成点i到点j是否连了一条单向道路,Cij表示i到j这条路的权值。
由此,第一个条件可以变成:点1的出度为1。
第二个条件:点n的入度为1
第三个条件:其他点的出度和入度是相等的。
由此题目所要求的就转化为比较点1的自环+点n的自环和点1到点n的最短路的大小,取最小值。
代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int MAXN=1e3;
int map[MAXN][MAXN],d[MAXN],vis[MAXN];
int n;
void spfa(int u)
{
queue<int> q;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
if(i==u)
d[i]=inf;
else
{
d[i]=map[u][i];
q.push(i);
vis[i]=1;
}
}
while(!q.empty())
{
int t=q.front();
q.pop();
vis[t]=0;
for(int i=1;i<=n;i++)
{
if(d[i]>d[t]+map[t][i])
{
d[i]=d[t]+map[t][i];
if(!vis[i])
{
vis[i]=1;
q.push(i);
}
}
}
}
}
int main(){
while(scanf("%d",&n)!=EOF)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
scanf("%d",&map[i][j]);
}
spfa(1);
int ans=d[n];
int d1=d[1];
spfa(n);
int d2=d[n];
printf("%d\n",min(ans,d1+d2));
}
return 0;
}