poj 2135 Farm Tour
题意:求从顶点1走到n再走回1的最短路径,每条边只能走一次。
解法:最小费用最大流,另设源点汇点,从源点到1连边,从n到汇点连边,这两条边都是容量为2,费用为0,表示要走两条包含源点(或汇点)的边,因为一去一回走的边不一样。。其余的边正常建就行,费用就是路径长度。。
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 #define N 1010 6 using namespace std; 7 const int inf=1<<30; 8 struct Edge{ 9 int u,v,c,len,next; 10 Edge(){} 11 Edge(int _u,int _v,int _c,int _len,int _next){ 12 u=_u;v=_v;c=_c;len=_len;next=_next; 13 } 14 }edge[N*N]; 15 int head[N],pre[N],cnt; 16 int dis[N]; 17 bool vis[N]; 18 int source,sink,n,m; 19 void init(){ 20 memset(head,-1,sizeof(head)); 21 cnt=0; 22 } 23 void addedge(int u,int v,int c,int len){ 24 edge[cnt]=Edge(u,v,c,len,head[u]); 25 head[u]=cnt++; 26 } 27 bool spfa(int st,int ed){ 28 memset(vis,0,sizeof(vis)); 29 memset(pre,-1,sizeof(pre)); 30 queue<int>Q; 31 for(int i=0;i<=n+1;i++)dis[i]=inf; 32 Q.push(st);dis[st]=0; 33 vis[st]=1; 34 while(!Q.empty()){ 35 int p=Q.front();Q.pop(); 36 vis[p]=0; 37 for(int k=head[p];k!=-1;k=edge[k].next){ 38 int v=edge[k].v,len=edge[k].len,c=edge[k].c; 39 if(c>0&&dis[v]>dis[p]+len){ 40 dis[v]=dis[p]+len; 41 pre[v]=k; 42 if(!vis[v]){ 43 Q.push(v); 44 vis[v]=1; 45 } 46 } 47 } 48 } 49 if(dis[ed]==inf)return 0; 50 return 1; 51 } 52 int solve(){ 53 int ans=0; 54 while(spfa(source,sink)){ 55 int minn=inf; 56 for(int k=pre[sink];k!=-1;k=pre[edge[k].u]) 57 minn=min(minn,edge[k].c); 58 for(int k=pre[sink];k!=-1;k=pre[edge[k].u]){ 59 edge[k].c-=minn; 60 edge[k^1].c+=minn; 61 } 62 ans+=minn*dis[sink]; 63 } 64 return ans; 65 } 66 int main(){ 67 while(~scanf("%d%d",&n,&m)){ 68 init(); 69 source=0; 70 sink=n+1; 71 for(int i=1;i<=m;i++){ 72 int u,v,w; 73 scanf("%d%d%d",&u,&v,&w); 74 addedge(u,v,1,w); 75 addedge(v,u,0,-w); 76 addedge(v,u,1,w); 77 addedge(u,v,0,-w); 78 } 79 addedge(source,1,2,0); 80 addedge(1,source,0,0); 81 addedge(n,sink,2,0); 82 addedge(sink,n,0,0); 83 int ans=solve(); 84 printf("%d\n",ans); 85 } 86 return 0; 87 }