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.
InputThe 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).OutputFor 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
这道题大致一看一脸懵,仔细一看还是懵。。。。。。。。
题意:
这个条件的意思就是从1这个点只能到到其他点中的一个点,简单一点就是1号点的出度为1
那么这个是n号点,只不过这个是n号点的入度为1
第三个条件就是除了一号点和n号点,其他点的出度等于入度
这个X是题上给出的限制条件,我们要使我们选出来的路符合这两个条件
既然X的值只能为0或1,那么我们只需要求从1到n的最小花费就可以了
就是求出来从起点到终点的最小花费,这个样子我们把题目上面输入的数存在邻接矩阵里面直接拿来用,这个矩阵正好满足上面三个条件,所以这是一个结果
但是我们要考虑环的存在,即起点形成一个环,终点n形成一个环,这个样子其他点的出入度为0也满足题意,但是要保证他不是自环,即必须保证有两个点
上代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<stdio.h> 2 #include<string.h> 3 #include<iostream> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 const int INF=0x3f3f3f3f; 8 int w[305][305],d[305],dis[305]; 9 queue<int>r; 10 void spay(int start,int ends) 11 { 12 memset(d,INF,sizeof(d)); 13 memset(dis,0,sizeof(dis)); 14 for(int i=1;i<=ends;++i) 15 { 16 if(i!=start) 17 { 18 dis[i]=1; 19 d[i]=w[start][i]; 20 r.push(i); 21 } 22 else 23 { 24 d[i]=INF; 25 } 26 } 27 while(!r.empty()) 28 { 29 int x=r.front(); 30 r.pop(); 31 dis[x]=0; 32 for(int i=1;i<=ends;++i) 33 { 34 if(d[i]>d[x]+w[x][i]) 35 { 36 d[i]=d[x]+w[x][i]; 37 if(!dis[i]) 38 { 39 dis[i]=1; 40 r.push(i); 41 } 42 } 43 } 44 } 45 } 46 int main() 47 { 48 int n; 49 while(~scanf("%d",&n)) 50 { 51 memset(w,0,sizeof(w)); 52 for(int i=1;i<=n;++i) 53 { 54 for(int j=1;j<=n;++j) 55 scanf("%d",&w[i][j]); 56 } 57 int q1,q2; 58 spay(1,n); 59 q1=d[n]; 60 q2=d[1]; 61 spay(n,n); 62 q2+=d[n]; 63 printf("%d ",min(q1,q2)); 64 } 65 return 0; 66 }
网搜的代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /* 2 HDU 4370 0 or 1 3 转换思维的题啊,由一道让人不知如何下手的题,转换为了最短路 4 基本思路就是把矩阵看做一个图,图中有n个点,1号点出度为1, 5 n号点入度为1,其它点出度和入度相等,路径长度都是非负数, 6 7 等价于一条从1号节点到n号节点的路径,故Xij=1表示需要经 8 过边(i,j),代价为Cij。Xij=0表示不经过边(i,j)。注意到Cij非负 9 且题目要求总代价最小,因此最优答案的路径一定可以对应一条简单路径。 10 11 最终,我们直接读入边权的邻接矩阵,跑一次1到n的最短路即可,记最短路为path。 12 13 漏了如下的情况B: 14 从1出发,走一个环(至少经过1个点,即不能 15 是自环),回到1;从n出发,走一个环(同理),回到n。 16 也就是1和n点的出度和入度都为1,其它点的出度和入度为0. 17 18 由于边权非负,于是两个环对应着两个简单环。 19 20 因此我们可以从1出发,找一个最小花费环,记代价为c1, 21 再从n出发,找一个最小花费环,记代价为c2。 22 (只需在最短路算法更新权值时多加一条记录即可:if(i==S) cir=min(cir,dis[u]+g[u][i])) 23 24 故最终答案为min(path,c1+c2) 25 */ 26 /* 27 本程序用SPFA来完成最短路。 28 但是由于要计算从出发点出发的闭环的路径长度。 29 所以要在普通SPFA的基础上做点变化。 30 31 就是把dist[start]设为INF。同时一开始并不是让出发点入队,而是让 32 出发点能够到达的点入队。 33 */ 34 #include<stdio.h> 35 #include<iostream> 36 #include<string.h> 37 #include<algorithm> 38 using namespace std; 39 40 const int INF=0x3f3f3f3f; 41 const int MAXN=330; 42 int cost[MAXN][MAXN];//保存路径长度的邻接矩阵 43 int dist[MAXN]; 44 int que[MAXN];//注意队列的循环利用,建成循环队列 45 bool vis[MAXN];//是否在队列中标记 46 47 void SPFA(int start,int n) 48 { 49 int front=0,rear=0; 50 for(int v=1;v<=n;v++)//初始化 51 { 52 if(v==start)//由于要找start的闭环,所以dist[start]设为INF,且不入队 53 { 54 dist[v]=INF; 55 vis[v]=false; 56 } 57 else if(cost[start][v]!=INF) 58 { 59 dist[v]=cost[start][v]; 60 que[rear++]=v; 61 vis[v]=true; 62 } 63 else//即dist[start][v]==INF情况,对本题没有这种情况 64 { 65 dist[v]=INF; 66 vis[v]=false; 67 } 68 } 69 70 while(front!=rear)//注意这个条件是不等,因为是循环队列 71 { 72 int u=que[front++]; 73 for(int v=1;v<=n;v++) 74 { 75 if(dist[v]>dist[u]+cost[u][v]) 76 { 77 dist[v]=dist[u]+cost[u][v]; 78 if(!vis[v])//不在队列 79 { 80 vis[v]=true; 81 que[rear++]=v; 82 if(rear>=MAXN) rear=0;//循环队列 83 } 84 } 85 } 86 vis[u]=false; 87 if(front>=MAXN)front=0; 88 } 89 90 } 91 int main() 92 { 93 //freopen("in.txt","r",stdin); 94 //freopen("out.txt","w",stdout); 95 int n; 96 while(scanf("%d",&n)!=EOF) 97 { 98 for(int i=1;i<=n;i++) 99 for(int j=1;j<=n;j++) 100 scanf("%d",&cost[i][j]); 101 SPFA(1,n); 102 int ans=dist[n];//1到n的最短路 103 int loop1=dist[1];//1的闭环长度 104 SPFA(n,n); 105 int loopn=dist[n];//n的闭环长度 106 ans=min(ans,loop1+loopn); 107 printf("%d ",ans); 108 } 109 return 0; 110 }