---恢复内容开始---
题意略。
这题在poj直接求最小费用会超时,但是题意也没说要求最优解。
根据线圈定理,如果一个跑完最费用流的残余网络中存在负权环,那么顺着这个负权环跑流量为1那么会得到更小的费用。
关键是坑在找环的起点。其实看了代码之后发现的确不难...
#include<stdio.h> #include<queue> #include<string.h> #define MAXN 300 #define MAXM 30002*4 #define INF 10000000 using namespace std; //起点编号必须最小,终点编号必须最大 bool vis[MAXN]; //spfa中记录是否在队列里边 int sum[105],nnum[MAXN],zhong; struct point{ int x,y,c; }from[105],to[105]; struct edge{ edge *next,*op; //op是指向反向边 int t,c,v; //t下一个点编号,c容量,v权值 }ES[MAXM],*V[MAXN]; //ES边静态邻接表,V点的编号 int N,M,S,T,EC=-1; //S源点最小,T汇点最大,EC当前边数 int demond[MAXN],sp[MAXN],prev[MAXN]; //spSPFA中记录距离,prev记录上一个点路径 edge *path[MAXN]; //与prev同步记录,记录到上一条边 int cal(point a,point b){ return max(a.x-b.x,b.x-a.x)+max(a.y-b.y,b.y-a.y)+1; } void addedge(int a,int b,int v,int c,int cc){ edge e1={V[a],0,b,c,v},e2={V[b],0,a,cc,-v}; ES[++EC]=e1;V[a]=&ES[EC]; ES[++EC]=e2;V[b]=&ES[EC]; V[a]->op=V[b];V[b]->op=V[a]; } bool SPFA(int st,int up){ int u,v; memset(nnum,0,sizeof(nnum)); memset(vis,0,sizeof(vis)); for(u=1;u<=up;u++){ sp[u]=INF; } queue<int>q; q.push(st); sp[st]=0; vis[st]=1; nnum[st]++; while(!q.empty()){ u=q.front(); vis[u]=0; q.pop(); for(edge *k=V[u];k;k=k->next){ v=k->t; if(k->c>0&&sp[u]+k->v<sp[v]){ sp[v]=sp[u]+k->v; prev[v]=u; path[v]=k; if(vis[v]==0){ nnum[v]++; if(nnum[v]>=up){ zhong=v; return 1; } vis[v]=1; q.push(v); } } } } return 0; } int argument(){ memset(vis,0,sizeof(vis)); int i,cost=1,flow=0; edge *e; for(i=zhong;;i=prev[i]){ if(vis[i]==0)vis[i]=1; else break; } zhong=i; bool ok=0; memset(vis,0,sizeof(vis)); for(i=zhong;;){ if(!vis[i])vis[i]=1; else break; e=path[i]; e->c-=cost;e->op->c+=cost; flow+=e->v*cost; vis[i]=1; i=prev[i]; //if(i==zhong)break; } return flow; } int maxcostflow(int tans,int up){ int Flow=tans; if(SPFA(1,up)){ Flow+=argument(); } return Flow; } void init(){ int n,m; while(scanf("%d%d",&n,&m)!=EOF){ EC=-1; memset(sum,0,sizeof(sum)); int tans=0; for(int i=0;i<MAXN;i++){ V[i]=NULL; } for(int i=0;i<n;i++){ scanf("%d%d%d",&from[i].x,&from[i].y,&from[i].c); } for(int i=0;i<m;i++){ scanf("%d%d%d",&to[i].x,&to[i].y,&to[i].c); } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ int tmp; scanf("%d",&tmp); addedge(i+1,j+1+n,cal(from[i],to[j]),INF,tmp); tans+=cal(from[i],to[j])*tmp; sum[j]+=tmp; } } T=n+m+1; for(int i=1;i<=m;i++){ addedge(i+n,T,0,to[i-1].c-sum[i-1],sum[i-1]); } int ans=maxcostflow(tans,T); if(ans==tans)puts("OPTIMAL"); else{ puts("SUBOPTIMAL"); for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ for(edge *k=V[j+1+n];k;k=k->next){ if(k->t==i+1){ printf("%d",k->c); if(j!=m-1)printf(" "); else printf(" "); break; } } } } } } } int main(){ init(); return 0; }
---恢复内容结束---