题意:0代表警察局,警局里面有k个警察,然后有1~n个城市,每个城市一个小偷,要想抓到第i个城市的小偷,必须先抓或同时抓一个1~i-1城市的小偷作为铺垫,一个警察一次可以抓多个小偷,一个小偷一次被一个警察抓就可以了,抓完小偷后,必须会到警察局0点,问你所有警察走过的路程和。
想法:显然警察越少越好,先找出城市与城市之间的最短路,floyd就可以。
1.设a到b的边的容量为flow,费用为fee:a->b(flow,fee)
2.点i拆成i和i+n
虚拟一个sink和source,建边:
source->0(k,0),表示可以出动这么多的警察。
0->sink(k,0),表示有的警察可以不使用。
0->i(1,dis[0][i]),表示警察可以走这里。
i->i+n(1,-inf),表示警察来过了这个城市,在这里有两个选择,回家或继续走下去,当然继续走下去的话,这个城市的小偷显然已经被抓住了。
i+n->kk(1,dis[i][k]),其中kk为标号大于i的城市,因为抓下面的小偷,这个走i是前提。
i+n->sink(1,dis[0][i]),表示回家。
还有一个就是特别要注意的地方,我被坑了,这里的inf=100000就够了,这里可以试着算一下,如果过大了比如我一开始定义成了0x7fffffff(就是最大的int),应为在最短路,和流量运算的时候有的数据就已经超出了int的范围,所以就没办法完成代码,导致你找不到错误。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define inf 100000 using namespace std; const int edges=30000; const int nodes=250; int map[nodes][nodes]; int n,m,k,s,t; int ans; struct node { int v,next; int flow,fee; }e[edges]; int head[nodes],cnt; void Init() { memset(head,-1,sizeof(head)); cnt=0; } void add(int a,int b,int c,int d) { e[cnt].v=b; e[cnt].flow=c; e[cnt].fee=d; e[cnt].next=head[a]; head[a]=cnt++; e[cnt].v=a; e[cnt].flow=0; e[cnt].fee=-d; e[cnt].next=head[b]; head[b]=cnt++; } class DINIC { public: int spath() { queue<int>q; while(!q.empty()) q.pop(); for(int i=0;i<=n*2+50;i++) dis[i]=inf; memset(vis,0,sizeof(vis)); memset(pe,-1,sizeof(pe)); vis[s]=1; dis[s]=0; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(dis[v]>dis[u]+e[i].fee&&e[i].flow>0) { dis[v]=dis[u]+e[i].fee; pe[v]=i; if(!vis[v]) { vis[v]=1; q.push(v); } } } } return dis[t]!=inf; } int Min(int a,int b) { if(a<b) return a; return b; } int dfs(int u,int flow) { int cost=0; if(u==t) { ans+=dis[t]; return flow; } for(int i=head[u];i+1;i=e[i].next) { int v=e[i].v; if(pe[v]==i&&e[i].flow>0) { int min=dfs(v,Min(e[i].flow,flow-cost)); if(min>0) { e[i].flow-=min; e[i^1].flow+=min; cost+=min; if(cost==flow) break; } else pe[v]=-1; } } return cost; } void result() { while(spath()) { int kk=dfs(s,inf); } } private: int dis[nodes],vis[nodes],pe[nodes]; }dinic; void Input() { for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) { if(i==j) map[i][j]=0; else map[i][j]=inf; } for(int i=1;i<=m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(a==b) continue; if(map[a][b]<=c) continue; map[a][b]=c; map[b][a]=c; } } void pretreatment() { for(int k=0;k<=n;k++) { for(int i=0;i<=n;i++) { for(int j=0;j<=n;j++) { if(map[i][k]+map[k][j]<map[i][j]) { map[i][j]=map[i][k]+map[k][j]; } } } } } void build_map() { s=2*n+1;t=2*n+2; add(s,0,k,0); add(0,t,k,0); for(int i=1;i<=n;i++) { add(0,i,1,map[0][i]); add(i,i+n,1,-inf); for(int j=i+1;j<=n;j++) { add(i+n,j,1,map[i][j]); } add(i+n,t,1,map[0][i]); } } void treatment() { ans=0; DINIC *p=&dinic; p->result(); printf("%d\n",ans+n*inf); } int main() { while(~scanf("%d%d%d",&n,&m,&k),n+m+k) { Init(); Input(); pretreatment(); build_map(); treatment(); } return 0; }