题意:有n(0<=n<=100)个点m(0<=m<=4000)条边的无向图,有k(0<=k<=25)个人从0点出发,依次占领1~n点,因为 i 被占领的时候会通知
i - 1 点,到达一个点的时候可以选择不占领,问最后<=k个人占领所有地方再走回来的最小值。
题解:floyd之后建图,因为要保证所有的点依次占领,所以每个点拆点流量为1费用为-inf(保证所有点都被占领),然后从j(j < i)建边到 i 流量为inf,费用为map[ j ][ i ]
(因为点的访问是要按照顺序的),然后从原点ss到i建容量为inf费用为map[0][i]的边,同理从i+n(i 拆的出边点)到t建容量为inf费用为map[i][0]的边,枚举k后,
重新建图,建s到ss容量为看,费用为0的边跑费用流即可。
Sure原创,转载请注明出处。
#include <iostream> #include <cstdio> #include <memory.h> #include <queue> #define MIN(a , b) ((a) < (b) ? (a) : (b)) using namespace std; const int inf = 100010; const int maxn = 102; const int maxe = 20000; const int maxm = 28; struct node { int v,w,c; int next; }edge[maxe << 1]; int head[maxn << 1],dis[maxn << 1],pre[maxn << 1],bj[maxn << 1]; int map[maxn][maxn]; bool vis[maxn << 1]; queue <int> Q; int m,n,k,idx,s,ss,t; void init() { for(int i=0;i<=n;i++) { map[i][i] = 0; for(int j=0;j<=n;j++) { map[i][j] = map[j][i] = inf; } } return; } void read() { int u,v,w; for(int i=0;i<m;i++) { scanf("%d %d %d",&u,&v,&w); if(map[u][v] > w) { map[u][v] = map[v][u] = w; } } return; } void floyd() { for(int k=0;k<=n;k++) { for(int i=0;i<=n;i++) { if(i == k || map[i][k] == inf) continue; for(int j=0;j<=n;j++) { if(j == i || j == k || map[k][j] == inf) continue; if(map[i][k] + map[k][j] < map[i][j]) { map[i][j] = map[i][k] + map[k][j]; map[j][i] = map[i][j]; } } } } return; } void addedge(int u,int v,int w,int c) { edge[idx].v = v; edge[idx].w = w; edge[idx].c = c; edge[idx].next = head[u]; head[u] = idx++; edge[idx].v = u; edge[idx].w = 0; edge[idx].c = -c; edge[idx].next = head[v]; head[v] = idx++; return; } void make(int lim) { memset(head,-1,sizeof(head)); memset(bj,-1,sizeof(bj)); s = idx = 0; ss = 2*n+1; t = 2*n+2; addedge(s,ss,lim,0); for(int i=1;i<=n;i++) { if(map[0][i] < inf) { addedge(ss,i,inf,map[0][i]); addedge(i+n,t,inf,map[i][0]); } addedge(i,i+n,1,-inf); for(int j=i+1;j<=n;j++) { if(map[i][j] < inf) { addedge(i+n,j,inf,map[i][j]); } } } return; } bool spfa(int st) { memset(vis,false,sizeof(vis)); memset(pre,-1,sizeof(pre)); while(!Q.empty()) { Q.pop(); } for(int i=0;i<=t;i++) { dis[i] = (i == st) ? 0 : inf; } Q.push(st); vis[st] = true; while(!Q.empty()) { int cur = Q.front(); Q.pop(); vis[cur] = false; for(int i=head[cur];i != -1;i=edge[i].next) { if(edge[i].w > 0 && dis[edge[i].v] > dis[cur] + edge[i].c) { dis[edge[i].v] = dis[cur] + edge[i].c; pre[edge[i].v] = i; if(vis[edge[i].v] == false) { vis[edge[i].v] = true; Q.push(edge[i].v); } } } } return dis[t] < inf; } void solve() { int res = inf; for(int i=1;i<=k;i++) { make(i); int ans = 0; while(spfa(s)) { int dx = inf; int top = t; while(top != s) { dx = MIN(dx , edge[pre[top]].w); top = edge[pre[top]^1].v; } top = t; while(top != s) { ans += dx * edge[pre[top]].c; edge[pre[top]].w -= dx; edge[pre[top]^1].w += dx; top = edge[pre[top]^1].v; } } res = MIN(res , ans + n * inf); } printf("%d\n",res); return; } int main() { while(scanf("%d %d %d",&n,&m,&k) && n+m+k) { init(); read(); floyd(); solve(); } return 0; }