题目链接
0 or 1
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1912 Accepted Submission(s): 575
Problem Description
Given a n*n matrix C
ij (1<=i,j<=n),We want to find a n*n matrix X
ij (1<=i,j<=n),which is 0 or 1.
Besides,X ij meets the following conditions:
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).
For example, if n=4,we can get the following equality:
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
Now ,we want to know the minimum of ∑C ij*X ij(1<=i,j<=n) you can get.
For sample, X 12=X 24=1,all other X ij is 0.
Besides,X ij meets the following conditions:
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).
For example, if n=4,we can get the following equality:
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
Now ,we want to know the minimum of ∑C ij*X ij(1<=i,j<=n) you can get.
Hint
For sample, X 12=X 24=1,all other X ij is 0.
Input
The input consists of multiple test cases (less than 35 case).
For each test case ,the first line contains one integer n (1<n<=300).
The next n lines, for each lines, each of which contains n integers, illustrating the matrix C, The j-th integer on i-th line is C ij(0<=C ij<=100000).
For each test case ,the first line contains one integer n (1<n<=300).
The next n lines, for each lines, each of which contains n integers, illustrating the matrix C, The j-th integer on i-th line is C ij(0<=C ij<=100000).
Output
For each case, output the minimum of ∑C
ij*X
ij you can get.
Sample Input
4 1 2 4 10 2 0 1 1 2 2 0 5 6 3 1 2
Sample Output
3
Author
Snow_storm
Source
在计算1和n的自环是要注意自环最小花费不一定是只经过除起点以外的一个点,因为这个路径虽说是双向的,但是从i到j的花费和从j到i的花费不相等,所以可能从起点经过多个点后再回来的总花费会比只经过一个点的最小花费低。因此使用了改进的spfa。详见代码。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=300+10;
const int inf=0x3f3f3f3f;
int n;
int cost[maxn][maxn];
int d[maxn],inq[maxn];
void spfa(int s) //改进的spfa
{
memset(inq,0,sizeof(inq));
queue<int> q;
for(int i=1;i<=n;i++)
{
if(i==s)
{
d[s]=inf;continue;
}
d[i]=cost[s][i];
inq[i]=1;
q.push(i);
}
while(!q.empty())
{
int u=q.front();
q.pop();
inq[u]=0;
for(int i=1;i<=n;i++)
{
if(d[i]>d[u]+cost[u][i])
{
d[i]=d[u]+cost[u][i];
if(inq[i]) continue;
inq[i]=1;
q.push(i);
}
}
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&cost[i][j]);
int ans=inf;
spfa(1);
int loop1=d[1];
ans=min(ans,d[n]);
spfa(n);
int loopn=d[n];
ans=min(ans,loop1+loopn);
printf("%d\n",ans);
}
}
循环队列版本:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
const int maxn=300+10;
const int inf=0x3f3f3f3f;
int n;
int cost[maxn][maxn];
int d[maxn],inq[maxn];
int que[maxn];
void spfa(int s)
{
memset(inq,0,sizeof(inq));
memset(que,0,sizeof(que));
queue<int> q;
int head=0,rear=0;
for(int i=1;i<=n;i++)
{
if(i==s)
{
d[s]=inf;continue;
}
d[i]=cost[s][i];
inq[i]=1;
que[rear++]=i;
}
while(head!=rear)
{
int u=que[head++];
inq[u]=0;
for(int i=1;i<=n;i++)
{
if(d[i]>d[u]+cost[u][i])
{
d[i]=d[u]+cost[u][i];
if(inq[i]) continue;
inq[i]=1;
que[rear++]=i;
if(rear>=maxn) rear=0;
}
}
if(head>=maxn) head=0;
}
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&cost[i][j]);
int ans=inf;
spfa(1);
int loop1=d[1];
ans=min(ans,d[n]);
spfa(n);
int loopn=d[n];
ans=min(ans,loop1+loopn);
printf("%d\n",ans);
}
}