题目大意:给一张带权线图,找出一条经过起点s和终点t的最小回路。
题目分析:建立网络,以s为源点,t为汇点,另每条边的容量为1,单位费用为边权值。求最小费用流,增广两次后的最小费用便是答案。
代码如下:
# include<iostream> # include<cstdio> # include<cmath> # include<string> # include<vector> # include<list> # include<set> # include<map> # include<queue> # include<cstring> # include<algorithm> using namespace std; # define LL long long # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)) # define CLL(a,b,n) fill(a,a+n,b) const double inf=1e30; const int INF=1<<30; const int N=105; struct Edge { int fr,to,cap,flow,cost; Edge(int _fr,int _to,int _cap,int _flow,int _cost):fr(_fr),to(_to),cap(_cap),flow(_flow),cost(_cost){} }; vector<Edge>edges; vector<int>G[N]; int p[N],a[N],d[N],inq[N]; void init(int n) { edges.clear(); REP(i,0,n) G[i].clear(); } void addEdge(int u,int v,int cost) { edges.push_back(Edge(u,v,1,0,cost)); edges.push_back(Edge(v,u,0,0,-cost)); int m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } bool BellmanFord(int s,int t,int &flow,int &cost) { CL(inq,0); CLL(d,INF,t+1); d[s]=0,inq[s]=1,p[s]=0,a[s]=INF; queue<int>q; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); inq[u]=0; REP(i,0,G[u].size()){ Edge &e=edges[G[u][i]]; if(d[e.to]>d[u]+e.cost&&e.cap>e.flow){ d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]){ inq[e.to]=1; q.push(e.to); } } } } if(d[t]==INF) return false; flow+=a[t]; cost+=a[t]*d[t]; for(int x=t;x!=s;x=edges[p[x]].fr){ edges[p[x]].flow+=a[t]; edges[p[x]^1].flow-=a[t]; } return true; } void solve(int s,int t) { int flow=0,cost=0; if(!BellmanFord(s,t,flow,cost)) printf("Back to jail\n"); else{ if(BellmanFord(s,t,flow,cost)) printf("%d\n",cost); else printf("Back to jail\n"); } } int main() { int s,t,n,m,a,b,c; while(scanf("%d",&n)&&n) { s=0,t=n-1; init(n); scanf("%d",&m); while(m--) { scanf("%d%d%d",&a,&b,&c); addEdge(a-1,b-1,c); addEdge(b-1,a-1,c); } solve(s,t); } return 0; }
时间: 2024-09-29 21:03:26