您的位置:首页 > 其它

hdu 4370 0 or 1(将数学问题转化为最短路)

2016-08-10 17:38 411 查看


题目链接


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 Cij (1<=i,j<=n),We want to find a n*n matrix Xij (1<=i,j<=n),which is 0 or 1.

Besides,Xij meets the following conditions:

1.X12+X13+...X1n=1

2.X1n+X2n+...Xn-1n=1

3.for each i (1<i<n), satisfies ∑Xki (1<=k<=n)=∑Xij (1<=j<=n).

For example, if n=4,we can get the following equality:

X12+X13+X14=1

X14+X24+X34=1

X12+X22+X32+X42=X21+X22+X23+X24

X13+X23+X33+X43=X31+X32+X33+X34

Now ,we want to know the minimum of ∑Cij*Xij(1<=i,j<=n) you can get.

Hint

For sample, X12=X24=1,all other Xij 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 Cij(0<=Cij<=100000).

 

Output

For each case, output the minimum of ∑Cij*Xij 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

2012 Multi-University Training Contest 8

这个题解很详细

在计算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
);
spfa(n);
int loopn=d
;
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
);
spfa(n);
int loopn=d
;
ans=min(ans,loop1+loopn);
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: