• BZOJ-1934 Vote 善意的投票 最大流+建图


    1934: [Shoi2007]Vote 善意的投票
    Time Limit: 1 Sec Memory Limit: 64 MB
    Submit: 1551 Solved: 951
    [Submit][Status][Discuss]

    Description
    幼儿园里有n个小朋友打算通过投票来决定睡不睡午觉。对他们来说,这个问题并不是很重要,于是他们决定发扬谦让精神。虽然每个人都有自己的主见,但是为了照顾一下自己朋友的想法,他们也可以投和自己本来意愿相反的票。我们定义一次投票的冲突数为好朋友之间发生冲突的总数加上和所有和自己本来意愿发生冲突的人数。 我们的问题就是,每位小朋友应该怎样投票,才能使冲突数最小?

    Input
    第一行只有两个整数n,m,保证有2≤n≤300,1≤m≤n(n-1)/2。其中n代表总人数,m代表好朋友的对数。文件第二行有n个整数,第i个整数代表第i个小朋友的意愿,当它为1时表示同意睡觉,当它为0时表示反对睡觉。接下来文件还有m行,每行有两个整数i,j。表示i,j是一对好朋友,我们保证任何两对i,j不会重复。

    Output
    只需要输出一个整数,即可能的最小冲突数。

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

    Sample Output
    1

    HINT
    在第一个例子中,所有小朋友都投赞成票就能得到最优解

    Source
    Day2

    这道题啊,刚看到我还真没确定是网络流,不过仔细想想,有了点眉目,想到建图策略后这道题就水了。。。
    首先超级源超级汇,超级源连接初始意愿为1的小朋友,超级汇连接初始意愿为0的小朋友,好朋友相连(双向边!!),边权都为1,Dinic出答案。。
    

    代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    
    int dis[9000]={0};
    int q[9000]={0},h,t;
    struct data{
        int to,next,v;
    }edge[100001];
    int head[9000]={0};
    int cnt=1;
    int yy[400]={0};
    int n,m,ans;
    
    void add(int u,int v,int w)
    {
        cnt++;
        edge[cnt].next=head[u];
        head[u]=cnt;
        edge[cnt].v=w;
        edge[cnt].to=v;
    }
    
    void init()
    {
        scanf("%d%d",&n,&m);
        for (int i=1; i<=n; i++)
            {
                scanf("%d",&yy[i]);
                if (yy[i]==1)
                    {
                        add(0,i,1);
                        add(i,0,0);
                    }
                else
                    {
                        add(i,n+1,1);
                        add(n+1,i,0);
                    }
            }
        for (int i=1; i<=m; i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                add(x,y,1);
                add(y,x,1);
            }//重要的是双向边,一开始忽略了。。。 
    }
    
    bool bfs()
    {
        memset(dis,-1,sizeof(dis));
        q[1]=0;dis[0]=1;
        h=0; t=1;
        while (h<t)
            {
                int j=q[++h],i=head[j];
                while (i)
                    {
                        if (dis[edge[i].to]<0 && edge[i].v>0)
                            {
                                dis[edge[i].to]=dis[j]+1;
                                q[++t]=edge[i].to;
                            }
                        i=edge[i].next;
                    }
            }
        if (dis[n+1]>0)
            return true;
        else
            return false;
    }
    
    int dfs(int loc,int low)
    {
        int now=0;
        if (loc==n+1) return low;
        int i=head[loc];
        while (i)
            {
                if (edge[i].v>0 && dis[edge[i].to]==dis[loc]+1 && (now=dfs(edge[i].to,min(low,edge[i].v))))
                    {
                        edge[i].v-=now;
                        edge[i^1].v+=now;
                        return now;
                    }
                i=edge[i].next;
            }
        return 0;
    }
    
    
    int main()
    {
        init();
        while (bfs())
            {
                int now=0;
                while ((now=dfs(0,0x7fffffff)))
                    ans+=now;
            }
        printf("%d",ans);
        return 0;   
    }
  • 相关阅读:
    java集合
    [编写高质量代码:改善java程序的151个建议]建议57 推荐在复杂字符串操作中使用正则表达式
    [编写高质量代码:改善java程序的151个建议]建议53 注意方法中传递的参数要求
    判断某一时间范围的方法
    c#读写xml文件
    冒泡排序
    C#使用正则表达式检测数字 char 和韩文
    三角形面积公式
    unity 绘制三角形
    中缀转后缀表达式
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5346234.html
Copyright © 2020-2023  润新知