scu oj 4442 Party(2015年四川省acm程序设计竞赛)(*)

58 篇文章 1 订阅
9 篇文章 0 订阅

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=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. ( 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分图,可以很容易求。现在考虑一只2种茶都可以喝的青蛙,这里是关键,我的解法是把这个青蛙拆成2个点,一个点代表他喝红茶,一个点代表他喝绿茶,首先这2个点是不能同时存在,那么必然有边,然后如果这只青蛙和其他只喝红茶的青蛙有矛盾关系,那么对应就是这个青蛙喝红茶和那个青蛙喝红茶不能同时存在,其他情况其实是类似的分析。这样拆点把矛盾关系图建立出来以后,实际上还是一个2分图,现在就是选出最大点权的点让这些点之间不存在矛盾关系。实际上就是点权最大独立集,转换成求点权最小覆盖的模型,就能很轻松的求解了。。。。。想这么久,果然是神建图。其实主要还是拆点。

VIEW CODE
[cpp]  view plain  copy
  1. //#pragma comment(linker, "/STACK:1024000000,1024000000")  
  2. #include<cstdio>  
  3. #include<cstring>  
  4. #include<algorithm>  
  5. #include<iostream>  
  6. #include<cmath>  
  7. #include<queue>  
  8. using namespace std;  
  9. const int mmax  = 2010;  
  10. const int inf = 0x3fffffff;  
  11.   
  12. struct node  
  13. {  
  14.     int flow;  
  15.     int en;  
  16.     int next;  
  17. }E[100*mmax];  
  18. int p[mmax];  
  19. int num;  
  20. void init()  
  21. {  
  22.     memset(p,-1,sizeof p);  
  23.     num=0;  
  24. }  
  25. void add(int st,int en,int flow)  
  26. {  
  27.     E[num].en=en;  
  28.     E[num].flow=flow;  
  29.     E[num].next=p[st];  
  30.     p[st]=num++;  
  31.     E[num].en=st;  
  32.     E[num].flow=0;  
  33.     E[num].next=p[en];  
  34.     p[en]=num++;  
  35. }  
  36.   
  37. int d[mmax];  
  38. int cur[mmax];  
  39. bool vis[mmax];  
  40. bool bfs(int st,int en)  
  41. {  
  42.     memset(vis,0,sizeof vis);  
  43.     d[st]=0;  
  44.     vis[st]=1;  
  45.     queue<int>q;  
  46.     q.push(st);  
  47.     while(!q.empty())  
  48.     {  
  49.         int x=q.front();  
  50.         q.pop();  
  51.         for(int i=p[x]; i+1; i=E[i].next)  
  52.         {  
  53.             int v=E[i].en;  
  54.             if(!vis[v]&&E[i].flow)  
  55.             {  
  56.                 vis[v]=1;  
  57.                 d[v]=d[x]+1;  
  58.                 q.push(v);  
  59.             }  
  60.         }  
  61.     }  
  62.     return vis[en];  
  63. }  
  64. int dfs(int st,int en,int  flow)  
  65. {  
  66.     if(st==en||flow==0)  
  67.         return flow;  
  68.     int f=0,dd;  
  69.     for(int &i=cur[st]; i+1;i=E[i].next)  
  70.     {  
  71.         int v=E[i].en;  
  72.         if(d[st]+1==d[v]&&(dd=dfs(v,en,min(flow,E[i].flow)))>0)  
  73.         {  
  74.             E[i].flow-=dd;  
  75.             E[i^1].flow+=dd;  
  76.             flow-=dd;  
  77.             f+=dd;  
  78.             if(flow==0)  
  79.                 break;  
  80.         }  
  81.     }  
  82.     return f;  
  83. }  
  84. int dinic(int st,int en,int n)  
  85. {  
  86.     int flow=0;  
  87.     while(bfs(st,en))  
  88.     {  
  89.         for(int i=0;i<=n;i++)  
  90.             cur[i]=p[i];  
  91.         flow+=dfs(st,en,inf);  
  92.     }  
  93.     return flow;  
  94. }  
  95.   
  96. vector<int>e[mmax];  
  97. int fg[mmax];  
  98. int w[mmax];  
  99. void dfs(int u)  
  100. {  
  101.     int SZ=e[u].size();  
  102.     for(int i=0;i<SZ;i++)  
  103.     {  
  104.         int v=e[u][i];  
  105.         if(d[v]==-1)  
  106.         {  
  107.             d[v]=d[u]^1;  
  108.             dfs(v);  
  109.         }  
  110.     }  
  111. }  
  112. int main()  
  113. {  
  114.     int n,m;  
  115.     while(~scanf("%d %d",&n,&m))  
  116.     {  
  117.         for(int i=0;i<mmax;i++)  
  118.             e[i].clear();  
  119.         for(int i=1;i<=n;i++)  
  120.             scanf("%d",&w[i]);  
  121.         int sum=0;  
  122.         for(int i=1;i<=n;i++)  
  123.         {  
  124.             scanf("%d",&fg[i]);  
  125.             if(fg[i]==3)  
  126.                 sum+=w[i];  
  127.         }  
  128.         for(int i=0;i<m;i++)  
  129.         {  
  130.             int u,v;  
  131.             scanf("%d %d",&u,&v);  
  132.             e[u].push_back(v);  
  133.             e[v].push_back(u);  
  134.         }  
  135.         init();  
  136.         memset(d,-1,sizeof d);  
  137.         for(int i=1;i<=n;i++)  
  138.         {  
  139.             if(d[i]==-1)  
  140.             {  
  141.                 d[i]=0;  
  142.                 dfs(i);  
  143.             }  
  144.         }  
  145.         int st=0,en=2*n+1;  
  146.         for(int i=1;i<=n;i++)  
  147.         {  
  148.             if(d[i]==0)  
  149.             {  
  150.                 if(fg[i]==1)  
  151.                     add(st,i,w[i]);  
  152.                 if(fg[i]==2)  
  153.                     add(i,en,w[i]);  
  154.                 if(fg[i]==3)  
  155.                 {  
  156.                     add(st,i,w[i]);  
  157.                     add(i,i+n,inf);  
  158.                     add(i+n,en,w[i]);  
  159.                 }  
  160.             }  
  161.             else  
  162.             {  
  163.                 if(fg[i]==1)  
  164.                     add(i,en,w[i]);  
  165.                 if(fg[i]==2)  
  166.                     add(st,i,w[i]);  
  167.                 if(fg[i]==3)  
  168.                 {  
  169.                     add(i,en,w[i]);  
  170.                     add(st,i+n,w[i]);  
  171.                     add(i+n,i,inf);  
  172.                 }  
  173.             }  
  174.         }  
  175.   
  176.         for(int u=1;u<=n;u++)  
  177.         {  
  178.             int Sz=e[u].size();  
  179.             for(int i=0;i<Sz;i++)  
  180.             {  
  181.                 int v=e[u][i];  
  182.                 if(d[u]==0 && d[v]==1)  
  183.                 {  
  184.                     if( (fg[u]==fg[v]) &&   (fg[u]!=3) )  
  185.                     {  
  186.                         if(fg[u]==1)  
  187.                             add(u,v,inf);  
  188.                         else  
  189.                             add(v,u,inf);  
  190.                     }  
  191.                     else if(  (fg[u]==fg[v]) &&   (fg[u]==3)  )  
  192.                     {  
  193.                         add(u,v,inf);  
  194.                         add(v+n,u+n,inf);  
  195.                     }  
  196.                     else if(fg[u]==3 || fg[v]==3 )  
  197.                     {  
  198.                         if(fg[u]==3)  
  199.                         {  
  200.                             if(fg[v]==1)  
  201.                                 add(u,v,inf);  
  202.                             else  
  203.                                 add(v,u+n,inf);  
  204.                         }  
  205.                         if(fg[v]==3)  
  206.                         {  
  207.                             if(fg[u]==1)  
  208.                                 add(u,v,inf);  
  209.                             else  
  210.                                 add(v+n,u,inf);  
  211.                         }  
  212.                     }  
  213.   
  214.                 }  
  215.             }  
  216.         }  
  217.         printf("%d\n",dinic(st,en,en)-sum);  
  218.     }  
  219.     return 0;  
  220. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值