zoukankan      html  css  js  c++  java
  • POJ 3648

    题目大意:

    有N对男女参加一场婚礼。其中一对是新郎和新娘(也就是本次婚礼的主角),其他N-1对都是已婚的夫妇。

    设X为0 ~ N-1之间的整数,用Xh和Xw表示一对男女,Xh为男性,Xw为女性。特别地,0h和0w表示新郎和新娘。

    这些人中有M对婚外情关系(也就是原文的adulterous relationships),婚外情可能是同性恋或者异性恋。

    现要将这N对男女安排在一张长桌子的两侧,要求:

    ①每一对男女都不能坐在同一侧;

    ②如果两个人有婚外情,那么他们不能同时坐在新娘的另一侧。

    求应该安排哪些人与新娘坐在同一侧,如果有多种方案,输出任意一种;如果不存在方案,输出"bad luck"(输出时不带引号)。

    N<=30。

    这道题简直各种神坑:

    ①诡异的题意!我读了好几遍题一直以为是N对男女的集体婚礼,后来结合讨论区和别人的博客才把题意搞懂……

    ②恶心的输入!!输入M对婚外情关系时,Xh和Yw之间可能没有空格!也就是说,用scanf读入时,"%s%s"是错误的,必须用"%d%c%d%c"。然而这点题面中并没有交代清楚……

    ③新郎和新娘也可能有婚外情!!如果忘了处理这种情况就很容易WA。(我的妈呀贵圈到底有多乱)

    不过模型很好建立。按照以下关系建图,然后跑一遍2-SAT。

    对于每个新郎和新娘以外的人,记他/她的编号为X,在图中相应建立两个节点:X表示该人与新娘坐在同侧,X'表示该人与新娘坐在异侧。

    对于要求①:设丈夫编号为X,妻子编号为Y,连4条边:X→Y',Y→X',X'→Y,Y'→X。其含义是:如果其中一人坐在新娘同侧,那么另一人必须坐在新娘异侧,反之亦然。

    对于要求②:设有婚外情的二人编号分别为X,Y。

    (1)如果其中某一人是新娘,不用处理;

    (2)如果X为新郎,连一条边Y'→Y,表示Y不能坐在新娘异侧。如果Y为新郎,则连一条边X'→X。

    (3)否则,连两条边:X'→Y,Y'→X。其含义是:如果其中一人坐在新娘异侧,那么另一人必须坐在新娘同侧。

    AC代码:

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <algorithm>
      4 #include <vector>
      5 #include <queue>
      6 #include <stack>
      7 #include <cctype>
      8 #include <utility>
      9 
     10 #define FILLC(arr, ch) memset(arr, ch, sizeof(arr))
     11 
     12 struct EListNode
     13 {
     14     int to, next;
     15     void assign(int t, int n) { to = t; next = n; }
     16 };
     17 
     18 template <int maxV, int maxE>
     19 struct EList
     20 {
     21     EListNode node[maxE + 1];
     22     int head[maxV + 1];
     23     int ecnt;
     24 
     25     void init()
     26     {
     27         FILLC(head, 0);
     28         ecnt = 0;
     29     }
     30 
     31     void access(int v, int& e, int& to)
     32     {
     33         e = head[v];
     34         to = node[e].to;
     35     }
     36     void access(int& e, int& to)
     37     {
     38         e = node[e].next;
     39         to = node[e].to;
     40     }
     41     bool isEnd(int e)
     42     {
     43         return e == 0;
     44     }
     45 
     46     void addEdge(int u, int v)
     47     {
     48         node[++ecnt].assign(v, head[u]);
     49         head[u] = ecnt;
     50     }
     51 };
     52 
     53 EList<128, 12800> elist;
     54 EList<128, 12800> compElist; //Graph after compressing SCCs
     55 int N, M;
     56 
     57 inline int getId(int x, char c)
     58 {
     59     return 2 * x - (c == 'h');
     60 }
     61 
     62 bool inputAndBuildGraph()
     63 {
     64     if (scanf("%d%d", &N, &M), N == 0)
     65         return false;
     66 
     67     elist.init();
     68     //char s1[5], s2[5];
     69     char cu, cv;
     70     for (int u, v, i = 0; i < M; i++)
     71     {
     72         //scanf("%s%s", s1, s2);
     73         scanf("%d%c%d%c", &u, &cu, &v, &cv);
     74         u = getId(u, cu);
     75         v = getId(v, cv);
     76         if (u > v)
     77             std::swap(u, v);
     78         if (u > 0) //not groom or bride
     79         {
     80             elist.addEdge(u + 2 * N, v);
     81             elist.addEdge(v + 2 * N, u); //adulterous pairs should not be both opposite the bride
     82         }
     83         else if (u == -1) //broom
     84             elist.addEdge(v + 2 * N, v);
     85     }
     86 
     87     for (int ih, iw, i = 1; i < N; i++)
     88     {
     89         ih = 2 * i - 1;
     90         iw = 2 * i;
     91         elist.addEdge(ih, iw + 2 * N);
     92         elist.addEdge(iw, ih + 2 * N); //husband and wife should not be on the same side
     93         elist.addEdge(ih + 2 * N, iw);
     94         elist.addEdge(iw + 2 * N, ih);
     95     }
     96 
     97     return true;
     98 }
     99 
    100 int dfn[128];
    101 int low[128];
    102 int sccId[128];
    103 bool inStack[128];
    104 int lastDfn;
    105 std::stack<int> stack;
    106 
    107 void initDfs()
    108 {
    109     FILLC(dfn, -1);
    110     lastDfn = 0;
    111 }
    112 
    113 inline void pushToStack(int v)
    114 {
    115     stack.push(v);
    116     inStack[v] = true;
    117 }
    118 
    119 inline int popFromStack()
    120 {
    121     int v = stack.top();
    122     stack.pop();
    123     inStack[v] = false;
    124     return v;
    125 }
    126 
    127 void tarjanDfs(int cur)
    128 {
    129     dfn[cur] = low[cur] = (++lastDfn);
    130     pushToStack(cur);
    131 
    132     int e, to;
    133     for (elist.access(cur, e, to); !elist.isEnd(e); elist.access(e, to))
    134     {
    135         if (dfn[to] == -1)
    136         {
    137             tarjanDfs(to);
    138             low[cur] = std::min(low[cur], low[to]);
    139         }
    140         else if (inStack[to])
    141             low[cur] = std::min(low[cur], dfn[to]);
    142     }
    143     if (dfn[cur] == low[cur])
    144         for (int v = popFromStack(); ; v = popFromStack())
    145         {
    146             sccId[v] = cur;
    147             if (v == cur)
    148                 break;
    149         }
    150 }
    151 
    152 bool check2SAT()
    153 {
    154     for (int i = 1; i <= (N - 1) * 2; i++)
    155         if (sccId[i] == sccId[i + N * 2])
    156             return false;
    157     return true;
    158 }
    159 
    160 int inDeg[128];
    161 int contra[128];
    162 bool chosen[128];
    163 
    164 void compressGraph()
    165 {
    166     compElist.init();
    167     FILLC(inDeg, 0);
    168 
    169     for (int v, e, i = 1; i <= (2 * N - 1) * 2; i++)
    170         for (elist.access(i, e, v); !elist.isEnd(e); elist.access(e, v))
    171         {
    172             if (sccId[i] == sccId[v])
    173                 continue;
    174             compElist.addEdge(sccId[v], sccId[i]);
    175             inDeg[sccId[i]] += 1;
    176         }
    177 
    178     for (int i = 1; i <= (N - 1) * 2; i++)
    179     {
    180         contra[sccId[i]] = sccId[i + 2 * N];
    181         contra[sccId[i + 2 * N]] = sccId[i];
    182     }
    183 }
    184 
    185 void chooseNodes()
    186 {
    187     std::queue<int> que;
    188     FILLC(chosen, 1);
    189 
    190     for (int i = 1; i <= (2 * N - 1) * 2; i++)
    191         if (sccId[i] == i && inDeg[i] == 0)
    192             que.push(i);
    193 
    194     while (!que.empty())
    195     {
    196         int cur = que.front();
    197         que.pop();
    198 
    199         int e, to;
    200         if (chosen[cur])
    201             chosen[contra[cur]] = false;
    202 
    203         for (compElist.access(cur, e, to); !compElist.isEnd(e); compElist.access(e, to))
    204         {
    205             inDeg[to] -= 1;
    206             if (inDeg[to] == 0)
    207                 que.push(to);
    208         }
    209     }
    210 }
    211 
    212 void solve()
    213 {
    214     initDfs();
    215     for (int i = 1; i <= (2 * N - 1) * 2; i++)
    216         if (dfn[i] == -1)
    217             tarjanDfs(i);
    218 
    219     if (!check2SAT())
    220     {
    221         printf("bad luck
    ");
    222         return;
    223     }
    224     compressGraph();
    225     chooseNodes();
    226 
    227     for (int i = 1; i <= (N - 1) * 2; i++)
    228     {
    229         if (chosen[sccId[i]])
    230             printf("%d%c ", (i + 1) / 2, i & 1 ? 'h' : 'w');
    231     }
    232     putchar('
    ');
    233 }
    234 
    235 int main()
    236 {
    237     while (inputAndBuildGraph())
    238         solve();
    239     return 0;
    240 }
  • 相关阅读:
    css样式初始化代码总结
    linux LVM逻辑卷的创建,扩容,缩减和删除
    MAC Jenkins安装 + Xcode + 蒲公英 + Testflight
    Linux rsyslog工具
    linux 中 Vi 和 Vim 的使用
    Zabbix实战--监控Nginx、MySQL与VM esxi主机、vSphere Client、JAVA应用
    Linux下netstat命令详解
    Debian 10上使用UFW设置防火墙
    开源网络安全检测工具——伏羲 Fuxi-Scanner
    CentOS8的web终端-cockpit,通过Cockpit管理KVM虚拟机
  • 原文地址:https://www.cnblogs.com/Onlynagesha/p/8459867.html
Copyright © 2011-2022 走看看