1. 程式人生 > >scu oj 4442 Party(2015年四川省acm程序設計競賽)

scu oj 4442 Party(2015年四川省acm程序設計競賽)

vector ++ _id ons hit 2015年 play border gre

Party

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 (1n103,0m104). The second line contains n integers w1,w2,,wn. (1wi106).

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

pi=3means it accepts both.

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

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


省賽過了非常久以後我才來看這道題目。

然後,yy了幾個晚上。最終發現果然是神一樣的建圖。 題目意思:有n個青蛙喝茶,有些青蛙僅僅能喝紅茶,有些青蛙僅僅能喝綠茶,有些青蛙紅茶綠茶都能夠喝。

如今m對青蛙之間有矛盾。有矛盾的青蛙他們不能喝一樣的茶,對於每一僅僅青蛙。能夠給他w[i]金幣。讓他不喝茶。他就不會和不論什麽青蛙矛盾了。最少須要給多少金幣讓他們之間沒有矛盾存在。這題裏面另一個非常重要的信息,我一開始沒有看出來。

這句話————“Luckily, frogs can be divided into 2 groups such that no two frogs in the same group dislike each other.”事實上這句話非常關鍵,它的意思就是這個矛盾關系圖不存在奇環,是一個2分圖。

有了這個條件。

我們如今考慮僅僅能喝一種茶的青蛙,紅和綠之間即使存在矛盾也沒有影響,那麽僅僅用考慮紅和紅,綠和綠之間的矛盾關系。如果不考慮2種都能喝的青蛙。那麽紅和紅,綠和綠都是單獨的求出最大點權獨立集。

因為是2分圖,能夠非常easy求。

如今考慮一僅僅2種茶都能夠喝的青蛙。這裏是關鍵,我的解法是把這個青蛙拆成2個點,一個點代表他喝紅茶,一個點代表他喝綠茶,首先這2個點是不能同一時候存在。那麽必定有邊,然後如果這僅僅青蛙和其它僅僅喝紅茶的青蛙有矛盾關系。那麽相應就是這個青蛙喝紅茶和那個青蛙喝紅茶不能同一時候存在,其它情況事實上是類似的分析。這樣拆點把矛盾關系圖建立出來以後,實際上還是一個2分圖。如今就是選出最大點權的點讓這些點之間不存在矛盾關系。

實際上就是點權最大獨立集。轉換成求點權最小覆蓋的模型,就能非常輕松的求解了。

。。。。想這麽久,果然是神建圖。事實上主要還是拆點。
VIEW CODE

//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
const int mmax  = 2010;
const int inf = 0x3fffffff;

struct node
{
    int flow;
    int en;
    int next;
}E[100*mmax];
int p[mmax];
int num;
void init()
{
    memset(p,-1,sizeof p);
    num=0;
}
void add(int st,int en,int flow)
{
    E[num].en=en;
    E[num].flow=flow;
    E[num].next=p[st];
    p[st]=num++;
    E[num].en=st;
    E[num].flow=0;
    E[num].next=p[en];
    p[en]=num++;
}

int d[mmax];
int cur[mmax];
bool vis[mmax];
bool bfs(int st,int en)
{
    memset(vis,0,sizeof vis);
    d[st]=0;
    vis[st]=1;
    queue<int>q;
    q.push(st);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=p[x]; i+1; i=E[i].next)
        {
            int v=E[i].en;
            if(!vis[v]&&E[i].flow)
            {
                vis[v]=1;
                d[v]=d[x]+1;
                q.push(v);
            }
        }
    }
    return vis[en];
}
int dfs(int st,int en,int  flow)
{
    if(st==en||flow==0)
        return flow;
    int f=0,dd;
    for(int &i=cur[st]; i+1;i=E[i].next)
    {
        int v=E[i].en;
        if(d[st]+1==d[v]&&(dd=dfs(v,en,min(flow,E[i].flow)))>0)
        {
            E[i].flow-=dd;
            E[i^1].flow+=dd;
            flow-=dd;
            f+=dd;
            if(flow==0)
                break;
        }
    }
    return f;
}
int dinic(int st,int en,int n)
{
    int flow=0;
    while(bfs(st,en))
    {
        for(int i=0;i<=n;i++)
            cur[i]=p[i];
        flow+=dfs(st,en,inf);
    }
    return flow;
}

vector<int>e[mmax];
int fg[mmax];
int w[mmax];
void dfs(int u)
{
    int SZ=e[u].size();
    for(int i=0;i<SZ;i++)
    {
        int v=e[u][i];
        if(d[v]==-1)
        {
            d[v]=d[u]^1;
            dfs(v);
        }
    }
}
int main()
{
    int n,m;
    while(~scanf("%d %d",&n,&m))
    {
        for(int i=0;i<mmax;i++)
            e[i].clear();
        for(int i=1;i<=n;i++)
            scanf("%d",&w[i]);
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&fg[i]);
            if(fg[i]==3)
                sum+=w[i];
        }
        for(int i=0;i<m;i++)
        {
            int u,v;
            scanf("%d %d",&u,&v);
            e[u].push_back(v);
            e[v].push_back(u);
        }
        init();
        memset(d,-1,sizeof d);
        for(int i=1;i<=n;i++)
        {
            if(d[i]==-1)
            {
                d[i]=0;
                dfs(i);
            }
        }
        int st=0,en=2*n+1;
        for(int i=1;i<=n;i++)
        {
            if(d[i]==0)
            {
                if(fg[i]==1)
                    add(st,i,w[i]);
                if(fg[i]==2)
                    add(i,en,w[i]);
                if(fg[i]==3)
                {
                    add(st,i,w[i]);
                    add(i,i+n,inf);
                    add(i+n,en,w[i]);
                }
            }
            else
            {
                if(fg[i]==1)
                    add(i,en,w[i]);
                if(fg[i]==2)
                    add(st,i,w[i]);
                if(fg[i]==3)
                {
                    add(i,en,w[i]);
                    add(st,i+n,w[i]);
                    add(i+n,i,inf);
                }
            }
        }

        for(int u=1;u<=n;u++)
        {
            int Sz=e[u].size();
            for(int i=0;i<Sz;i++)
            {
                int v=e[u][i];
                if(d[u]==0 && d[v]==1)
                {
                    if( (fg[u]==fg[v]) &&   (fg[u]!=3) )
                    {
                        if(fg[u]==1)
                            add(u,v,inf);
                        else
                            add(v,u,inf);
                    }
                    else if(  (fg[u]==fg[v]) &&   (fg[u]==3)  )
                    {
                        add(u,v,inf);
                        add(v+n,u+n,inf);
                    }
                    else if(fg[u]==3 || fg[v]==3 )
                    {
                        if(fg[u]==3)
                        {
                            if(fg[v]==1)
                                add(u,v,inf);
                            else
                                add(v,u+n,inf);
                        }
                        if(fg[v]==3)
                        {
                            if(fg[u]==1)
                                add(u,v,inf);
                            else
                                add(v+n,u,inf);
                        }
                    }

                }
            }
        }
        printf("%d\n",dinic(st,en,en)-sum);
    }
    return 0;
}


scu oj 4442 Party(2015年四川省acm程序設計競賽)