ZOJ3885 2015July月赛 E 费用流

The Exchange of Items

Bob lives in an ancient village, where transactions are done by one item exchange with another. Bob is very clever and he knows what items will become more valuable later on. So, Bob has decided to do some business with villagers.

At first, Bob has N kinds of items indexed from 1 to N, and each item has Ai. There are M ways to exchanges items. For the ith way (Xi, Yi), Bob can exchange one Xith item to one Yith item, vice versa. Now Bob wants that his ith item has exactly Bi, and he wonders what the minimal times of transactions is.

Input

There are multiple test cases.
For each test case: the first line contains two integers: N and M (1 <= N, M <= 100).
The next N lines contains two integers: Ai and Bi (1 <= Ai, Bi <= 10,000).
Following M lines contains two integers: Xi and Yi (1 <= Xi, Yi <= N).
There is one empty line between test cases.

Output

For each test case output the minimal times of transactions. If Bob could not reach his goal, output -1 instead.

Sample Input

2 1
1 2
2 1
1 2

4 2
1 3
2 1
3 2
2 3
1 2
3 4
Sample Output

1
-1

题意就是Bob有N个物品, 标号1~N, 接下来的N行为描述:第i件物品初始有Ai个,他最后想变成Bi个,他有M种交换物品的方法, 每一种描述为Xi,Yi, 表示他可以用一个Xi换一个Yi, 或者反过来…

最后问你如果可以交换成功的话,至少要交换多少次.

不难看出是个费用流…但是因为建图的时候挫了, 把每个物品拆成了两个点,然后忘记给i’ - j这样的连一条边..所以WA了下…

建图的话就是一个超级源连向N个点,流量为初始拥有值.然后N个点再连向N+1~2N的点上流量为INF,N~2*N的点再连到汇点上, 流量为目标值.以上边花费为0; 然后对于M种交换方式,每一种四条边, i->j’ , j->i’, i’->j, j’->i…流量为INF, 花费为1

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<string>
#include<stack>
#include<queue>
#include<vector>
#include<map>
#include<set>
#include<iostream>
#define pb push_back
using namespace std;
typedef unsigned long long ULL;
typedef long long LL;
const int MAXN = 505;
const int MAXM = 50005;
const int INF = 0x3f3f3f3f;
struct Edge
{
    int to,next,cap,flow,cost;
} edge[MAXM];
int head[MAXN],tol;
int pre[MAXN],dis[MAXN];
bool vis[MAXN];
int have[MAXN], want[MAXN];
int N;
void init(int n)
{
    N = n;
    tol = 0;
    memset(head, -1, sizeof(head));
}
void addedge(int u,int v,int cap,int cost)
{
    edge[tol].to = v;
    edge[tol].cap = cap;
    edge[tol].cost = cost;
    edge[tol].flow = 0;
    edge[tol].next = head[u];
    head[u] = tol++;
    edge[tol].to = u;
    edge[tol].cap = 0;
    edge[tol].cost = -cost;
    edge[tol].flow = 0;
    edge[tol].next = head[v];
    head[v] = tol++;
}
bool spfa(int s,int t)
{
    queue<int>q;
    for(int i = 0; i < N; i++)
    {
        dis[i] = INF;
        vis[i] = false;
        pre[i] = -1;
    }
    dis[s] = 0;
    vis[s] = true;
    q.push(s);
    while(!q.empty())
    {
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u]; i != -1; i = edge[i].next)
        {
            int v = edge[i].to;
            if(edge[i].cap > edge[i].flow &&
                    dis[v] > dis[u] + edge[i].cost )
            {
                dis[v] = dis[u] + edge[i].cost;
                pre[v] = i;
                if(!vis[v])
                {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    if(pre[t] == -1)return false;
    else return true;
}
int minCostMaxflow(int s,int t,int &cost)
{
    int flow = 0;
    cost = 0;
    while(spfa(s,t))
    {
        //puts("   **test1** ");
        int Min = INF;
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            if(Min > edge[i].cap - edge[i].flow)
                Min = edge[i].cap - edge[i].flow;
        }
        for(int i = pre[t]; i != -1; i = pre[edge[i^1].to])
        {
            edge[i].flow += Min;
            edge[i^1].flow -= Min;
            cost += edge[i].cost * Min;
        }
        flow += Min;
    }
    return flow;
}
void solve()
{
    int n, m;
    while(~scanf("%d %d", &n, &m)){
        init(2*n+2);
        int sum = 0, haveSum = 0;
        for(int i=1; i<=n; i++){
            scanf("%d %d\n", &have[i], &want[i]);
            sum += have[i];
            haveSum += want[i];
            addedge(0, i, have[i], 0);
            addedge(i, i+n, INF, 0);
            addedge(i+n, 2*n+1, want[i], 0);
        }
        for(int i=0; i<m; i++){
            int u, v;
            scanf("%d %d", &u, &v);
            addedge(u, v+n, INF, 1);
            addedge(v, u+n, INF, 1);
            addedge(u+n, v, INF, 1);
            addedge(v+n, u, INF, 1);
        }
        if(haveSum != sum){
            puts("-1");
            continue;
        }
        int ans = 0;
        //puts("1");
        int k = minCostMaxflow(0, 2*n+1, ans);
        //printf("k : %d sum : %d ans : %d\n", k, sum, ans);
        if(k == sum) printf("%d\n", ans);
        else puts("-1");
        //puts("2");
    }
}
int main(void)
{
#ifdef DK
    freopen("/home/dk/桌面/1.in","r",stdin);
#endif // DK
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值