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

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 (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=3means
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

省赛过了非常久以后我才来看这道题目。

然后,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;
}
时间: 2024-08-24 01:27:56

scu oj 4442 Party(2015年四川省acm程序设计竞赛)的相关文章

没有什么不可能—记山东省第六届ACM程序设计竞赛(退役总结帖)

大一下学期,第一次听说了ACM这个词,当时每周六也开设了培训课,但我好像一次也没有去过,当时对这个词并没有什么太大的印象.后来学院里引进了自己的OJ,那时候我连基本的输入输出格式都不懂,当经历了一堆的WA,TLE之后突然换来的一个AC竟带来了莫名的喜悦.后来学院举办了第一届ACM程序设计竞赛,我报名参加了新秀赛和团队赛.三个小时的新秀赛,当时貌似做出了三道,意外的拿到了一等奖,这也成为了我大学生活的一个重要转折点.四个小时的团队赛,做得很艰难,各种不会,最后只做出了一道,排在三等奖的末尾.比赛之

华南师大 2017 年 ACM 程序设计竞赛新生初赛题解

华南师大 2017 年 ACM 程序设计竞赛新生初赛题解 华南师范大学第很多届 ACM 程序设计竞赛新生赛(初赛)在 2017 年 11 月 20 日 - 27 日成功举行,共有 146 名同学有效参赛(做出 1 题).进入决赛的资格初定为完成并通过 5 题或以上,决赛时间是 12 月 3 日,地点未定. 题解 被你们虐了千百遍的题目和 OJ 也很累的,也想要休息,所以你们别想了,行行好放过它们,我们来看题解吧... A. 诡异的计数法 Description cgy 太喜欢质数了以至于他计数也

开锁魔法II 哈尔滨理工大学第五届ACM程序设计竞赛

规律:a[i][j]=     1/i * a[i-1][j-1]      +      (i-1)/i * a[i-1][j];  (少一个盒子时使用j-1 次魔法的概率)   (少一个盒子时使用j次魔法的概率) 公式推导如下: 设a[i][j]为打开i个盒子正好需要j次魔法的情况. ① 1->1 ② 1->1 , 2->2;        两次 1->2 , 2->1;        一次 ③ 1->1 , 2->2 , 3->3;     三次 1-

SCU 4436 Easy Math 2015年四川省赛题

题目链接:http://acm.scu.edu.cn/soj/problem/4436/ 题意:给你n个整数,求这n个数的平方根和是否是一个整数: 解题思路:如果这题每个数给他算出来,必然费时间,可能还会超精度,所以巧妙的方法就是判断这些整数是否全是完全平方数,如果有一个不是,则他们的平方根和肯定不是一个整数. AC代码: #include <cstdio> #include <cmath> #include <cstring> #include <algorit

2016河南省第九届ACM程序设计竞赛【正式赛真题】

A题:表达式求值 时间限制:1000 ms  |  内存限制:65535 KB 描述 假设表达式定义为:1. 一个十进制的正整数 X 是一个表达式.2. 如果 X 和 Y 是 表达式,则 X+Y, X*Y 也是表达式; *优先级高于+.3. 如果 X 和 Y 是 表达式,则 函数 Smax(X,Y)也是表达式,其值为:先分别求出 X ,Y值的各位数字之和,再从中选最大数.4.如果 X 是 表达式,则 (X)也是表达式.例如:表达式 12*(2+3)+Smax(333,220+280) 的值为 6

2015 ACM-ICPC国际大学生程序设计竞赛北京赛区网络赛 1002 Mission Impossible 6

题目链接: #1228 : Mission Impossible 6 解题思路: 认真读题,细心模拟,注意细节,就没有什么咯!写这个题解就是想记录一下rope的用法,以后忘记方便复习. rope(块状链表)属于SGI STL的一部分,不属于ISO C++标准库,但libstdc++-v3也包含了扩展,在头文件#include<ext/rope>,using namespace __gnu_cxx命名空间中.可以在很短的时间内实现快速的插入.删除和查找字符串. rope.size()    返回

山东省第一届acm程序设计竞赛题解

缺c 计算几何没看 f一个模拟,不想写,难度不大,J,因为时间挺早的,题目都比较简单,没什么难度,组队出个8题还是轻松的 A:水题 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1e3+5; 4 string s[maxn]; 5 6 bool judge(string s1,string s2){ 7 if(s1.length()>s2.length())return 1; 8 int len=s1.

山东省第四届ACM程序设计竞赛A题:Rescue The Princess(数学+计算几何)

Rescue The Princess Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 412  Solved: 168[Submit][Status][Web Board] Description Several days ago, a beast caught a beautiful princess and the princess was put in prison. To rescue the princess, a prince who

“师创杯”山东理工大学第九届ACM程序设计竞赛

A:签到题,直接LL做 B:模拟.没什么好写的 C:求k * m % n == 0最小的k,k = n / (gcd(n,m)) D:bfs E:把第一和第二棵树hash起来,然后在第一棵树每个节点找一下相等的 F:规律题 考虑len == 1的时候,年份范围是2009 - 2018len == 2的时候年份范围是2019 - 2118..然后递增,l[i] = r[i - 1] + 1,r[i] = l[i] + 10^i - 1.再随便特判一下就做完了 G:题意很迷,题意就是输入一篇文章,可