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.
Sample Input
4 1 2 4 10 2 0 1 1 2 2 0 5 6 3 1 2
Sample Output
3
在比赛的时候我的思路是X矩阵只可能是0 or 1,所以分为三种情况,分别求出最小值,然后再取最小值。
但是后来发现还是有少情况的时候。反正就是没往图论的方向想,赛后看解题报告,才恍然大悟。
这道题关键在于看懂题的隐含意思。
三个条件可以理解为:第一个点出度为1,最后一个点入度为0. 据说在比赛时的数据水了,没有考虑有环的情况。
因为第一个点有可能有入度,最后一个点也可能有出度。所以还可以看做是第一个点的一个环和最后一个点的一个环的和。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxint=1e7;
const int mm=400;
const int mn=1111111;
int dis[mm],head[mm],q[mm],vis[mm];
int c[mm][mm];
int n,edge;
int ver[mn],next[mn],cost[mn];
void addedge(int u,int v,int c)
{
ver[edge]=v,cost[edge]=c,next[edge]=head[u],head[u]=edge++;
}
int spfa(int src)
{
int i,u,v,l,r=0,tmp,cir;
for(i=0;i<=n;i++) dis[i]=maxint;
dis[q[r++]=src]=0;
vis[src]=1;
cir=maxint;
for(l=0;l!=r;(++l>mm)?l=0:l)//第三个条件非常重要,这个也给忘记了,呜呜。。。。
for(i=head[u=q[l]],vis[u]=0;i>=0;i=next[i])
{
if(ver[i]==src&&dis[u]+cost[i]<cir) cir=dis[u]+cost[i];
if(dis[v=ver[i]]>(tmp=dis[u]+cost[i]))
{
dis[v]=tmp;
if(vis[v]) continue;
vis[q[r++]=v]=1;
if(r>=mm) r=0;
}
}
return cir;
}
int main()
{
int i,j,tot,ans;
while(~scanf("%d",&n))
{
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
scanf("%d",&c[i][j]);
edge=0;
memset(head,-1,sizeof(head));//忘记初始化head了,找了好长时间。。。
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i!=j)
addedge(i,j,c[i][j]);
ans=spfa(1);
tot=dis[n];
int ans1=spfa(n);
ans=min(tot,ans+ans1);
printf("%d\n",ans);
}
return 0;
}