zoukankan      html  css  js  c++  java
  • HDU1814(Peaceful Commission) 【2-SAT DFS暴力求最小字典序的模板】

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1814

    题意:给出一个数n,代表有n个党派,每个党派要求派出其中一个人去参加会议,且只能派出一人。给出m,m行每行给出a, b.代表处于不同党派中的a, b也具有矛盾关系,a, b其中也只能有一位去参加会议。这2 * n个人的编号为1 ~ 2 * n,其中 2 * i 与 2 * i - 1是属于同一个党派。要求找到一个编号字典序最小的方案。

    思路:

    1.每个集合中只有2个元素,并且给出部分元素之间的限制关系,典型的2-sat问题。

    2.找到对立点,建‘矛盾边’,用tarjan缩点,再判断对立点是否处在一个强连通分量中,若处在则无解,若都不处在就有解。这种思路在这道题是不可行的,因为题目要求最小字典序输出。

    3.由于要保证最小字典序,我们可以用染色法来求解。每个人的编号我们默认 -1 ,这样就可以运用 ^1 运算来处理同一帮派中的2个人。从0号开始遍历到2 * n - 1号人,这样寻找方案就是最小字典序。

    4.扩展若同一对点的编号是不连续的,例如0-5,1-9,3-4. 那么我们就要用结构体排序(结构体中2个变量分别代表同一帮派中的2个人的编号),将同一点对中小的那个点按照从小到大的顺序排序,保证遍历的时候的字典序。(加矛盾边不需要处理)

    代码里的注释很详细。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #define mem(a, b) memset(a, b, sizeof(a))
     4 
     5 int n, m;
     6 int head[16100], cnt;
     7 int vis[16100], sum, node[16100];
     8 
     9 struct Edge
    10 {
    11     int to, next;
    12 }edge[20000 * 2];
    13 
    14 void add(int a, int b)
    15 {
    16     edge[++ cnt].to = b;
    17     edge[cnt].next = head[a];
    18     head[a] = cnt;
    19 }
    20 
    21 void init()
    22 {
    23     mem(head, -1), cnt = 0;
    24     mem(vis, 0);
    25 }
    26 
    27 int dfs(int now)
    28 {
    29     if(vis[now ^ 1])//若帮派中另一个人已经被选择,则自己一定不会被选择,返回0 
    30         return 0;
    31     if(vis[now])//若自己已经被选择,则不用再dfs了,已经找过从自己出发的方案 
    32         return 1;
    33     node[sum ++] = now;//记录查找过程中的点是哪些 
    34     vis[now] = 1;
    35     for(int i = head[now]; i != -1; i = edge[i].next)//不同帮派中的矛盾关系 
    36     {
    37         int to = edge[i].to;
    38         if(!dfs(to))//这些边代表'必须', 不能选b,就必须选择b ^ 1,若b ^ 1找不到合理方案,说明就不存在方案了,返回0 
    39             return 0;
    40     }
    41     return 1;
    42 }
    43 
    44 int two_sat() //返回是否存在方案 
    45 {
    46     for(int i = 0; i < 2 * n; i += 2) //由小到大遍历, 保证在有合理的方案的情况下的字典序 
    47     {
    48         if(!vis[i] && !vis[i ^ 1]) //若遍历到有帮派中2人都未被标记, 则确定之前的标记,代表是合法方案的一部分, sum清为0 
    49         {
    50             sum = 0;
    51             if(!dfs(i))//暴力寻找的过程中发现不存在,那么该过程中被标记的点都重新处理为未被标记 
    52             {
    53                 while(sum)
    54                     vis[node[-- sum]] = 0;
    55                 if(!dfs(i ^ 1))//若帮派中另一个人也找不到合理方案,那么就不存在方案了,直接retrun 0 
    56                     return 0;
    57             }
    58         }
    59     }
    60     return 1;
    61 }
    62 
    63 int main()
    64 {
    65     while(scanf("%d%d", &n, &m)!=EOF)
    66     {
    67         init();
    68         for(int i = 1; i <= m; i ++)
    69         {
    70             int a, b;
    71             scanf("%d%d", &a, &b);
    72             a --, b --;  //形成 ^1 运算关系
    73             add(a, b ^ 1), add(b, a ^ 1);
    74         }
    75         if(two_sat())
    76         {
    77             for(int i = 0; i < 2 * n; i += 2)
    78             {
    79                 if(vis[i])
    80                     printf("%d
    ", i + 1);
    81                 else
    82                     printf("%d
    ", (i ^ 1) + 1);
    83             }
    84         }
    85         else
    86             printf("NIE
    ");
    87     }
    88     return 0;
    89 }
    View Code
  • 相关阅读:
    06.04 html
    汉企第一天
    Django之ajax
    Diango之图书管理系统编辑
    Django之模型层&ORM操作
    Django 之模板层
    Django之 路由层
    Django之ORM简单操作(一)
    迭代器、可迭代对象、迭代器对象、生成器、生成器对象、枚举对象
    装饰器
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/10917118.html
Copyright © 2011-2022 走看看