• BZOJ 1934 善意的投票


    题目链接:

    https://www.lydsy.com/JudgeOnline/problem.php?id=1934

    题目大意:

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

    思路:

    最小割,所有赞成的与源点连边,所有反对的与汇点连边,朋友之间连边,求最小割即可。

      1 #include<bits/stdc++.h>
      2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
      3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时
      4 #define Min(a, b) ((a) < (b) ? (a) : (b))
      5 #define Mem(a) memset(a, 0, sizeof(a))
      6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
      7 #define MID(l, r) ((l) + ((r) - (l)) / 2)
      8 #define lson ((o)<<1)
      9 #define rson ((o)<<1|1)
     10 #define Accepted 0
     11 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
     12 using namespace std;
     13 inline int read()
     14 {
     15     int x=0,f=1;char ch=getchar();
     16     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     17     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
     18     return x*f;
     19 }
     20 typedef long long ll;
     21 const int maxn = 2000 + 10;
     22 const int MOD = 1000000007;//const引用更快,宏定义也更快
     23 const int INF = 1e9 + 7;
     24 const double eps = 1e-6;
     25 
     26 struct edge
     27 {
     28     int u, v, c, f;
     29     edge(int u, int v, int c, int f):u(u), v(v), c(c), f(f){}
     30 };
     31 vector<edge>e;
     32 vector<int>G[maxn];
     33 int level[maxn];//BFS分层,表示每个点的层数
     34 int iter[maxn];//当前弧优化
     35 int m;
     36 void addedge(int u, int v, int c)
     37 {
     38     e.push_back(edge(u, v, c, 0));
     39     e.push_back(edge(v, u, 0, 0));
     40     m = e.size();
     41     G[u].push_back(m - 2);
     42     G[v].push_back(m - 1);
     43 }
     44 void BFS(int s)//预处理出level数组
     45 //直接BFS到每个点
     46 {
     47     memset(level, -1, sizeof(level));
     48     queue<int>q;
     49     level[s] = 0;
     50     q.push(s);
     51     while(!q.empty())
     52     {
     53         int u = q.front();
     54         q.pop();
     55         for(int v = 0; v < G[u].size(); v++)
     56         {
     57             edge& now = e[G[u][v]];
     58             if(now.c > now.f && level[now.v] < 0)
     59             {
     60                 level[now.v] = level[u] + 1;
     61                 q.push(now.v);
     62             }
     63         }
     64     }
     65 }
     66 int dfs(int u, int t, int f)//DFS寻找增广路
     67 {
     68     if(u == t)return f;//已经到达源点,返回流量f
     69     for(int &v = iter[u]; v < G[u].size(); v++)
     70         //这里用iter数组表示每个点目前的弧,这是为了防止在一次寻找增广路的时候,对一些边多次遍历
     71         //在每次找增广路的时候,数组要清空
     72     {
     73         edge &now = e[G[u][v]];
     74         if(now.c - now.f > 0 && level[u] < level[now.v])
     75             //now.c - now.f > 0表示这条路还未满
     76             //level[u] < level[now.v]表示这条路是最短路,一定到达下一层,这就是Dinic算法的思想
     77         {
     78             int d = dfs(now.v, t, min(f, now.c - now.f));
     79             if(d > 0)
     80             {
     81                 now.f += d;//正向边流量加d
     82                 e[G[u][v] ^ 1].f -= d;
     83     //反向边减d,此处在存储边的时候两条反向边可以通过^操作直接找到
     84                 return d;
     85             }
     86         }
     87     }
     88     return 0;
     89 }
     90 int Maxflow(int s, int t)
     91 {
     92     int flow = 0;
     93     for(;;)
     94     {
     95         BFS(s);
     96         if(level[t] < 0)return flow;//残余网络中到达不了t,增广路不存在
     97         memset(iter, 0, sizeof(iter));//清空当前弧数组
     98         int f;//记录增广路的可增加的流量
     99         while((f = dfs(s, t, INF)) > 0)
    100         {
    101             flow += f;
    102         }
    103     }
    104     return flow;
    105 }
    106 int x[maxn];
    107 int main()
    108 {
    109     int n, m;
    110     scanf("%d%d", &n, &m);
    111     int s = 0, t = n + 1;
    112     for(int i = 1; i <= n; i++)
    113     {
    114         scanf("%d", &x[i]);
    115         if(x[i])addedge(s, i, 1);//所有赞成的与源点连边
    116         else addedge(i, t, 1);//所有反对的与汇点连边
    117     }
    118     while(m--)
    119     {
    120         int u, v;
    121         scanf("%d%d", &u, &v);
    122         if(x[u] && !x[v])//u赞成 v反对
    123             addedge(u, v, 1);
    124         if(x[v] && !x[u])//v赞成 u反对
    125             addedge(v, u, 1);//最小割
    126     }
    127     printf("%d
    ", Maxflow(s, t));
    128     return Accepted;
    129 }
  • 相关阅读:
    josn类库引用
    WPF圆角按钮
    C#实现某一属性值变化时触发事件 Form1_changeEvent是对应的事件
    C#winform生成安装包
    特性
    反射可以动态调用对象(一般是类)的名称,属性,方法等。具体见下。重要
    原子操作 和Inerlocked 常用于多线程同步
    spingboot 配置多个数据源报错
    Address already in use: JVM_Bind 端口被占用的几个解决办法
    数据库问题(一)
  • 原文地址:https://www.cnblogs.com/fzl194/p/9711467.html
Copyright © 2020-2023  润新知