题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4411
【题意】给定N+1个点,距离,K个人,问,每人从0开始按照升序访问节点然后回到0,每个节点被访问一次的最小距离和。
【分析】费用流问题,因为每个点只能被访问一次,所以拆点iX,iY,容量为1,Floyd后建图,因为每个点都必须被访问,所以费用设为-M,这样找最小费用的时候一定会选取iX-iY。另外加源点到汇点的边(s,t,k,0),防止负权回路。这是一类好题啊。
ZKW_flow 109 ms:
1 #include<functional> 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 #include<queue> 9 #define REP(i, n) for(int i=0; i<n; i++) 10 #define FF(i, a, b) for(int i=a; i<b; i++) 11 #define CLR(a, b) memset(a, b, sizeof(a)) 12 #define PB push_back 13 using namespace std; 14 15 const int MAXN = 455; 16 const int MAXE = MAXN*MAXN/2; 17 const int INF = 1e8; 18 struct ZKW_flow 19 { 20 int st, ed, ecnt, n; 21 int head[MAXN]; 22 int cap[MAXE], cost[MAXE], to[MAXE], next[MAXE], dis[MAXN]; ; 23 24 void init() 25 { 26 memset(head, 0, sizeof(head)); 27 ecnt = 2; 28 } 29 30 void AddEdge(int u, int v, int cc, int ww) 31 { 32 cap[ecnt] = cc; 33 cost[ecnt] = ww; 34 to[ecnt] = v; 35 next[ecnt] = head[u]; 36 head[u] = ecnt++; 37 cap[ecnt] = 0; 38 cost[ecnt] = -ww; 39 to[ecnt] = u; 40 next[ecnt] = head[v]; 41 head[v] = ecnt++; 42 } 43 44 void SPFA() 45 { 46 REP(i, n+1) dis[i] = INF; 47 priority_queue<pair<int, int> > Q; 48 dis[st] = 0; 49 Q.push(make_pair(0, st)); 50 while(!Q.empty()) 51 { 52 int u = Q.top().second, d = -Q.top().first; 53 Q.pop(); 54 if(dis[u] != d) continue; 55 for(int p = head[u]; p; p = next[p]) 56 { 57 int &v = to[p]; 58 if(cap[p] && dis[v] > d + cost[p]) 59 { 60 dis[v] = d + cost[p]; 61 Q.push(make_pair(-dis[v], v)); 62 } 63 } 64 } 65 REP(i, n+1) dis[i] = dis[ed] - dis[i]; 66 } 67 68 int minCost, maxFlow; 69 bool use[MAXN]; 70 71 int add_flow(int u, int flow) 72 { 73 if(u == ed) 74 { 75 maxFlow += flow; 76 minCost += dis[st] * flow; 77 return flow; 78 } 79 use[u] = true; 80 int now = flow; 81 for(int p = head[u]; p; p = next[p]) 82 { 83 int &v = to[p]; 84 if(cap[p] && !use[v] && dis[u] == dis[v] + cost[p]) 85 { 86 int tmp = add_flow(v, min(now, cap[p])); 87 cap[p] -= tmp; 88 cap[p^1] += tmp; 89 now -= tmp; 90 if(!now) break; 91 } 92 } 93 return flow - now; 94 } 95 96 bool modify_label() 97 { 98 int d = INF; 99 REP(u, n+1) if(use[u]) 100 for(int p = head[u]; p; p = next[p]) 101 { 102 int &v = to[p]; 103 if(cap[p] && !use[v]) d = min(d, dis[v] + cost[p] - dis[u]); 104 } 105 if(d == INF) return false; 106 REP(i, n+1) if(use[i]) dis[i] += d; 107 return true; 108 } 109 110 int Mincost(int ss, int tt, int nn) 111 { 112 st = ss, ed = tt, n = nn; 113 minCost = maxFlow = 0; 114 SPFA(); 115 while(true) 116 { 117 while(true) 118 { 119 CLR(use, 0); 120 if(!add_flow(st, INF)) break; 121 } 122 if(!modify_label()) break; 123 } 124 return minCost; 125 } 126 } MC; 127 128 const int maxn = 111; 129 int n, m, k; 130 131 int mp[maxn][maxn]; 132 133 134 void solve() 135 { 136 int nn = 2*n + 3; 137 int s = 0, ss = 2*n + 1, t = ss + 1; 138 MC.init(); 139 MC.AddEdge(s, ss, k,0); 140 MC.AddEdge(ss,t,k,0); 141 int tmp = 1e7; 142 for (int i=1;i<=n;i++) 143 { 144 MC.AddEdge(ss, i, 1, mp[0][i]); 145 MC.AddEdge(i, i+n, 1, -tmp); 146 MC.AddEdge(i+n, t,1,mp[0][i]); 147 for (int j=i+1;j<=n;j++) 148 { 149 MC.AddEdge(i+n, j, 1, mp[i][j]); 150 } 151 } 152 printf("%d\n",MC.Mincost(s,t,nn) + n * tmp); 153 return ; 154 } 155 int main() 156 { 157 while (scanf("%d%d%d",&n,&m,&k)==3) 158 { 159 if (n == 0) 160 break; 161 for (int i=0;i<=n;i++) 162 { 163 for (int j=0;j<=n;j++){ 164 mp[i][j] = INF; 165 } 166 } 167 while (m--) 168 { 169 int x, y, z; 170 scanf("%d%d%d",&x,&y,&z); 171 mp[x][y] = min(mp[x][y],z); 172 mp[y][x] = min(mp[y][x],z); 173 } 174 175 for (int k=0;k<=n;k++) 176 for (int i=0;i<=n;i++) 177 for (int j=0;j<=n;j++) 178 { 179 mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); 180 } 181 182 solve(); 183 } 184 return 0; 185 }
另外一个费用流模板 62ms:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<queue> 7 using namespace std; 8 #define maxn 1010 9 #define maxm 20010 10 const int inf = 0x3f3f3f3f; 11 12 struct Nod { 13 int b, nxt; 14 int cap, cst; 15 void init(int b, int nxt, int cap, int cst) { 16 this->b = b; 17 this->nxt = nxt; 18 this->cap = cap; 19 this->cst = cst; 20 } 21 }; 22 struct MinCost { 23 int E[maxn]; 24 int n; 25 Nod buf[maxm * 2]; 26 int len; 27 int p[maxn]; 28 void init(int n) { 29 this->n = n; 30 memset(E, 255, sizeof(E)); 31 len = 0; 32 } 33 void AddEdge(int a, int b, int cap, int cst) { 34 buf[len].init(b, E[a], cap, cst); 35 E[a] = len++; 36 buf[len].init(a, E[b], 0, -cst); 37 E[b] = len++; 38 } 39 bool spfa(int source, int sink) { 40 static queue<int> q; 41 static int d[maxn]; 42 memset(d, 63, sizeof(d)); 43 memset(p, 255, sizeof(p)); 44 d[source] = 0; 45 q.push(source); 46 int u, v; 47 while (!q.empty()) { 48 u = q.front(); 49 q.pop(); 50 for (int i = E[u]; i != -1; i = buf[i].nxt) { 51 v = buf[i].b; 52 if (buf[i].cap > 0 && d[u] + buf[i].cst < d[v]) { 53 d[v] = d[u] + buf[i].cst; 54 p[v] = i; 55 q.push(v); 56 } 57 } 58 } 59 return d[sink] != inf; 60 } 61 int Mincost(int source, int sink) { 62 int minCost = 0, maxFlow = 0;//需要maxFlow的话,想办法返回 63 while (spfa(source, sink)) { 64 int neck = inf; 65 for (int t = p[sink]; t != -1; t = p[buf[t ^ 1].b])//buf[t^壹].b是父节点 66 neck = min(neck, buf[t].cap); 67 maxFlow += neck; 68 for (int t = p[sink]; t != -1; t = p[buf[t ^ 1].b]) { 69 buf[t].cap -= neck; 70 buf[t ^ 1].cap += neck; 71 minCost += buf[t].cst * neck; 72 } 73 } 74 return minCost; 75 } 76 } MC; 77 78 int n, m, k; 79 80 int mp[maxn][maxn]; 81 82 83 void solve() 84 { 85 int nn = 2*n + 3; 86 int s = 0, ss = 2*n + 1, t = ss + 1; 87 MC.init(nn); 88 MC.AddEdge(s, ss, k,0); 89 MC.AddEdge(ss,t,k,0); 90 int tmp = 1e7; 91 for (int i=1;i<=n;i++) 92 { 93 MC.AddEdge(ss, i, 1, mp[0][i]); 94 MC.AddEdge(i, i+n, 1, -tmp); 95 MC.AddEdge(i+n, t,1,mp[0][i]); 96 for (int j=i+1;j<=n;j++) 97 { 98 MC.AddEdge(i+n, j, 1, mp[i][j]); 99 } 100 } 101 printf("%d\n",MC.Mincost(s,t) + n * tmp); 102 return ; 103 } 104 int main() 105 { 106 while (scanf("%d%d%d",&n,&m,&k)==3) 107 { 108 if (n == 0) 109 break; 110 for (int i=0;i<=n;i++) 111 { 112 for (int j=0;j<=n;j++){ 113 mp[i][j] = inf; 114 } 115 } 116 while (m--) 117 { 118 int x, y, z; 119 scanf("%d%d%d",&x,&y,&z); 120 mp[x][y] = min(mp[x][y],z); 121 mp[y][x] = min(mp[y][x],z); 122 } 123 124 for (int k=0;k<=n;k++) 125 for (int i=0;i<=n;i++) 126 for (int j=0;j<=n;j++) 127 { 128 mp[i][j] = min(mp[i][j], mp[i][k] + mp[k][j]); 129 } 130 131 solve(); 132 } 133 return 0; 134 }