hdu 4411 最小费用流
思路:主要就是要把一个每个城市拆为两个点,建一条容量为1,费用为-inf的边,保证每个城市都会被遍历。
/*最小费用最大流*/ #include<iostream> #include<cstring> #include<cstring> #include<cmath> #include<cstdio> using namespace std; const int Maxn = 1010; const int inf = 1000010; struct Edge{ int v; int val; int cost; int next; }edge[Maxn*100]; int head[Maxn],n,g[Maxn][Maxn],m,k; int e; int pre[Maxn], pos[Maxn]; int dis[Maxn], que[Maxn*100]; bool vis[Maxn]; void add(int u, int v, int val, int cost) { edge[e].v = v; edge[e].val = val; edge[e].cost = cost; edge[e].next = head[u]; head[u] = e++; edge[e].v = u; edge[e].val = 0; edge[e].cost = -cost; edge[e].next = head[v]; head[v] = e++; } void init() { memset(head,-1,sizeof(head)); for(int i=0;i<Maxn;i++) for(int j=0;j<Maxn;j++) g[i][j]=inf; e=0; } bool spfa(int s, int t) { int i; memset(pre, -1, sizeof(pre)); memset(vis, 0, sizeof(vis)); int Head, tail; Head = tail = 0; for(i = 0; i < Maxn; i++) dis[i] = inf; que[tail++] = s; pre[s] = s; dis[s] = 0; vis[s] = 1; while(Head != tail) { int now = que[Head++]; vis[now] = 0; for(i=head[now]; i != -1; i = edge[i].next) { int adj = edge[i].v; //cout<<now<<" "<<adj<<" "<<dis[now]<<" "<<edge[i].cost<<" "<<dis[adj]<<" "<<edge[i].val<<endl; if(edge[i].val > 0 && dis[now] + edge[i].cost < dis[adj]) { dis[adj] = dis[now] + edge[i].cost; pre[adj] = now; pos[adj] = i; if(!vis[adj]) { vis[adj] = 1; que[tail++] = adj; } } } } return pre[t] != -1; } int MinCostFlow(int s, int t, int flow) { int i; int cost = 0; flow = 0; while(spfa(s, t)) { int f = inf; for(i = t; i != s; i = pre[i]) if (edge[pos[i]].val < f) f = edge[pos[i]].val; flow += f; cost += dis[t] * f; for(i = t; i != s; i = pre[i]) { edge[pos[i]].val -= f; edge[pos[i] ^ 1].val += f; } // cout<<cost<<endl; } return cost; // flow是最大流值 } void floyd() { int i,j,k; for(k=0;k<=n;k++) for(i=0;i<=n;i++) for(j=0;j<=n;j++) { if(g[k][j]==inf) continue; g[i][j]=min(g[i][j],g[i][k]+g[k][j]); } } void build(int lim) { memset(head,-1,sizeof(head)); e=0; int ss = 0; int s = 2*n+1; int t = 2*n+2; add(s,ss,lim,0); for(int i=1;i<=n;i++) { if(g[0][i] < inf) { add(ss,i,1,g[0][i]); add(i+n,t,1,g[i][0]); } add(i,i+n,1,-inf); for(int j=i+1;j<=n;j++) { if(g[i][j] < inf) { add(i+n,j,1,g[i][j]); } } } add(ss,t,k,0); return; } int solve() { int i,j; int ans; ans=inf; build(k); ans=min(ans,MinCostFlow(n+n+1,n+n+2,0)+n*inf); return ans; } int main() { int i,j,u,v,c; while(scanf("%d%d%d",&n,&m,&k)!=EOF,n||m||k) { init(); for(i=1;i<=m;i++) { scanf("%d%d%d",&u,&v,&c); if(g[u][v]>c) g[u][v]=g[v][u]=c; } floyd(); printf("%d\n",solve()); } return 0; }