POJ 3648 - Wedding - 2-SAT

题目大意:

有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\n");
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('\n');
233 }
234 
235 int main()
236 {
237     while (inputAndBuildGraph())
238         solve();
239     return 0;
240 }

 

转载于:https://www.cnblogs.com/Onlynagesha/p/8459867.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值