Party

来源:互联网 发布:php和java对比 编辑:程序博客网 时间:2024/04/29 06:24

题目描述:

G. Party

Time Limit: 1000ms

Memory Limit: 65536KB
64-bit integer IO format: %lld Java class name: Main

Submit Status

n frogs are invited to a tea party. Frogs are conveniently numbered by 1,2,…,n.

The tea party has black and green tea in service. Each frog has its own preference. He or she may drink only black/green tea or accept both.

There are m pairs of frogs who dislike each other. They fight when they are serving the same type of tea.

Luckily, frogs can be divided into 2 groups such that no two frogs in the same group dislike each other.

Frogs like gems. If the i-th frog can be paid wi gems instead of serving tea, it will not fight with others anymore.

The party manager has to dicide how to serve tea/pay gems to avoid fights, minimizing the total gems paid.

Input

The input consists of multiple tests. For each test:

The first line contains 2 integers n,m (1≤n≤103,0≤m≤104). The second line contains n integers w1,w2,…,wn. (1≤wi≤106).

The third line contains n integers p1,p2,…,pn. (1≤pi≤3). pi=1 means the i-th frog drinks only black tea. pi=2 means it drinks only green one, while pi=3 means it accepts both.

Each of the following m lines contains 2 integers ai,bi, which denotes frog ai and bi dislike each other. (1≤ai,bi≤n)

Output

For each test, write 1 integer which denotes the minimum total gems paid.

Sample Input
2 1
1 1
3 3
1 2
2 1
1 1
2 2
1 2
3 2
2 1 2
1 3 2
1 2
2 3

Sample Output
0
1
1

题解:

很好的一道网络流.
首先给出的图是一个二分图,那么我们先按照他给的染色,黑色和白色.之后有青蛙和绿茶和红茶. 现在用最小割来描述好多边不能出现的情况:(1)同样茶不同颜色并且有边的边,这个边必须通过去掉两边某一只青蛙,很好弄最小割.(2)能喝两种茶的青蛙,首先我们拆点,然后两个点连一条边,这条边不能断(INF),意味着两个点不能同时存在,然后两个点当成正常的去连,我们最后在答案中减去一个数(因为一定会去掉至少一个点).

重点:

去掉一个点就能够覆盖一堆边,并且要求边全部去掉关键是每一条边只会有二分图两边的各一个点来控制.

代码:

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxV = 4000 + 100;//点的个数const int maxE = 40000 + 100;//边的个数const int INF = 2000000000+100;//最大值,一般没用.用于初始化limitconst int maxn = 1e3+100;struct Edge{    int from, to, cap, flow, next;    Edge(int _from = 0, int _to = 0, int _cap = 0, int _flow = 0, int _next = 0)    {        from = _from;        to = _to;        cap = _cap;        flow = _flow;        next = _next;    }};struct Dinic{    int s, t;    Edge edges[2*maxE];    // 边数的两倍,注意啊啊啊    int tot; //边的放的位置    int head[maxV];   // 邻接表,head[u]代表最后一条边在edges里面的位置。    int cur[maxV];         // 当前弧指针,每次从head中拷贝过去。    bool vis[maxV];        // BFS使用    int d[maxV];           // 从起点到i的距离    int que[maxV], fro, tail;//BFS用的queue    void init()    {        tot = 0;        memset(head, -1, sizeof(head));    }    void addEdge(int from, int to, int cap)//第一条边的下标一定是偶数好    {        //printf("%d  %d  %d\n", from, to, cap);        edges[tot] = Edge(from, to, cap, 0, head[from]);        head[from] = tot;        tot++;        edges[tot] = Edge(to, from, 0, 0, head[to]);        head[to] = tot;        tot++;    }    bool BFS()    {        memset(vis, 0, sizeof(vis));        fro = tail = 0;        que[tail] = s;        tail++;        vis[s] = 1;        d[s] = 0;        while(fro < tail)        {            int u = que[fro];            fro++;            for(int i = head[u]; i!=-1; i = edges[i].next)            {                Edge &e = edges[i];                if(!vis[e.to] && e.cap > e.flow)                {                    vis[e.to] = 1;                    d[e.to] = d[u]+1;                    que[tail] = e.to;                    tail++;                }            }        }        return vis[t];    }    int DFS(int u, int exFlow)    {        if(u == t || exFlow == 0) return exFlow;        int flow = 0, f;        for(int &i = cur[u]; i!=-1; i = edges[i].next)        {            Edge &e = edges[i];            if(d[u]+1 == d[e.to])            {                f = DFS(e.to, min(exFlow, e.cap - e.flow));                if(f > 0)                {                    e.flow += f;                    edges[i^1].flow -= f;                    flow += f;                    exFlow -= f;                    if(exFlow==0)                        break;                }            }        }        return flow;    }    // 求s-t最大流。如果最大流超过limit,则只找一个流量为limit的流    int Maxflow(int s, int t, int limit)    {        this->s = s;        this->t = t;        int flow = 0;        while(BFS())        {            memcpy(cur, head, sizeof(cur));            flow += DFS(s, limit - flow);            if(flow == limit) break; // 达到流量限制,直接退出        }        return flow;    }};Dinic g;struct info{    int a, b, c, d;    info(int _a=0, int _b=0, int _c=0, int _d=0)    {        a = _a;        b = _b;        c = _c;        d = _d;    }};info no[maxn];int n, m, w[maxn], tag[maxn], color[maxn];vector<int> G[maxn];void dfs(int u, int c){    color[u] = c;    for(int i = 0; i<G[u].size(); i++)    {        int v = G[u][i];        if(color[v]==-1)        {            dfs(v, 1-c);        }    }}void solve(){    memset(color, -1, sizeof(color));    for(int i = 1; i<=n; i++)    {        if(color[i]==-1)        {            dfs(i, 0);        }    }    int tot = 0;    for(int i = 1; i<=n; i++)    {        if(tag[i]==2)        {            no[i].a = ++tot;            no[i].b = ++tot;            no[i].c = ++tot;            no[i].d = ++tot;        }        else if(tag[i]==0)        {            no[i].a = ++tot;            no[i].b = ++tot;        }        else        {            no[i].c = ++tot;            no[i].d = ++tot;        }    }    g.s = ++tot;    g.t = ++tot;    g.init();    int ans = 0;    for(int i = 1; i<=n; i++)    {        if(color[i]==0&&(tag[i]==0||tag[i]==2))        {            for(int j = 0; j<G[i].size(); j++)            {                int v = G[i][j];                if(color[v]==1&&(tag[v]==0||tag[v]==2))                {                    g.addEdge(no[i].b, no[v].a, INF);                }            }        }        if(color[i]==1&&(tag[i]==1||tag[i]==2))        {            for(int j = 0;j<G[i].size();j++)            {                int v = G[i][j];                if(color[v]==0&&(tag[v]==1||tag[v]==2))                {                    g.addEdge(no[i].d, no[v].c, INF);                }            }        }        if(tag[i]==0)        {            g.addEdge(no[i].a, no[i].b, w[i]);        }        else if(tag[i]==1)        {            g.addEdge(no[i].c, no[i].d, w[i]);        }        else        {            g.addEdge(no[i].a, no[i].b, w[i]);            g.addEdge(no[i].c, no[i].d, w[i]);            if(color[i]==0)                g.addEdge(no[i].b, no[i].c, INF);            else                g.addEdge(no[i].d, no[i].a, INF);            ans -= w[i];        }        if(color[i]==0&&(tag[i]==0||tag[i]==2))        {            g.addEdge(g.s, no[i].a, INF);        }        if(color[i]==1&&(tag[i]==1||tag[i]==2))        {            g.addEdge(g.s, no[i].c, INF);        }        if(color[i]==0&&(tag[i]==1||tag[i]==2))        {            g.addEdge(no[i].d, g.t, INF);        }        if(color[i]==1&&(tag[i]==0||tag[i]==2))        {            g.addEdge(no[i].b, g.t, INF);        }    }    ans += g.Maxflow(g.s, g.t, INF);    printf("%d\n", ans);}int main(){    freopen("7Gin.txt", "r", stdin);    //freopen("7Gout.txt", "w", stdout);    while(scanf("%d%d", &n, &m) != EOF)    {        for(int i = 1;i<=n;i++)        {            G[i].clear();            scanf("%d", &w[i]);        }        for(int i = 1;i<=n;i++)        {            int tmp;            scanf("%d", &tmp);            if(tmp==1)                tag[i] = 1;            else if(tmp==2)                tag[i] = 0;            else                tag[i] = 2;        }        for(int i = 1;i<=m;i++)        {            int a, b;            scanf("%d%d", &a, &b);            G[a].push_back(b);            G[b].push_back(a);        }        solve();    }    return 0;}
0 0
原创粉丝点击