题目大意:
有n个物品想进行物品交换,给出n个物品的初始值A[i], 最终想要得到的值B[i],给出m种交换方式,问是否有满足要求的交换,有的话输出最小交换次数,否则输出-1;
思路分析:
①:有一个前提,只有当所有物品的初始值的和等于最终状态下的值的和,才有可能有满足条件的交换;
②:如何物品的初始值大于最终状态的值,就让这个点与源点相连,容量为两个值的差,表示该物品有这么有这些是需要交换出的,费用为0;
③:如何物品的初始值小于最终状态的值,就让这个点与汇点相连,容量为两个值的差,表示该物品有这么有这些是需要交换进的,费用为0;
④:根据题里给出的m中交换方式,在这些点中连边,容量为INF,费用为1;
⑤:当最大流等于所有连向汇点的交换的差值的和时,可以输出最小费用;
代码实现:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int N=210;
const int M=40400;
const int INF=0x3f3f3f3f;
int n,m,s,t,top,head[N],pre[N],path[N],dis[N],minflow[N],sum_cost,vis[N],sum_flow;
struct Edge{
int to,next,flow,cost;
Edge(int _to=0,int _next=0,int _flow=0,int _cost=0):to(_to),next(_next),flow(_flow),cost(_cost){}
}edge[M];
void Addedge(int from,int to,int flow,int cost){
edge[top]=Edge(to,head[from],flow,cost);
head[from]=top++;
edge[top]=Edge(from,head[to],0,-cost);
head[to]=top++;
}
int Spfa(){
queue<int> q;
memset(dis,0x3f,sizeof(dis));
memset(minflow,0x3f,sizeof(minflow));
memset(pre,-1,sizeof(pre));
memset(vis,0,sizeof(vis));
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=edge[i].next){
if(edge[i].flow&&dis[edge[i].to]>dis[u]+edge[i].cost){
dis[edge[i].to]=dis[u]+edge[i].cost;
pre[edge[i].to]=u;
path[edge[i].to]=i;
minflow[edge[i].to]=Min(minflow[u],edge[i].flow);
if(!vis[edge[i].to]){
vis[edge[i].to]=1;
q.push(edge[i].to);
}
}
}
}
if(dis[t]==INF) return 0;
sum_cost+=minflow[t]*dis[t];
sum_flow+=minflow[t];
int u=t;
while(u!=s){
edge[path[u]].flow-=minflow[t];
edge[path[u]^1].flow+=minflow[t];
u=pre[u];
}
return 1;
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(head,-1,sizeof(head));
top=sum_cost=s=sum_flow=0;
t=n+1;
int a,b,sum=0,sum_a=0,sum_b=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&a,&b);
sum_a+=a,sum_b+=b;
if(a>b) Addedge(s,i,a-b,0);
else if(b>a) Addedge(i,t,b-a,0),sum+=b-a;
}
for(int i=0;i<m;++i){
scanf("%d%d",&a,&b);
Addedge(a,b,INF,1);
Addedge(b,a,INF,1);
}
if(sum_a!=sum_b){
printf("-1\n");
continue;
}
while(Spfa());
if(sum_flow!=sum) printf("-1\n");
else printf("%d\n",sum_cost);
}
}