日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

POJ 3648 Wedding

發布時間:2024/4/14 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 POJ 3648 Wedding 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

POJ_3648

首先要注意兩個和算法無關地方:①題目的輸入數據存在諸如“2w5h”的情況,因此直接用scanf(“%s%s”,b1,b2)去讀取數據會WA。②題目中的意思是找出一組能和新娘坐在一起的人,而題目中描述的對于人的限制都是指的對面的,因此我們要先利用已知把對面的人的序列構造出來,再輸出對應的新娘這邊的人的序列即可。

這是我的第一個2-SAT的題目,做完一題相當于復習了好多圖論的知識……總的來說,這類問題一般的步驟是這個樣子的:

①根據已知條件建圖。比如這一題,已知的條件是xy不能同時坐在對面(注意,與不能同時坐在一起是不同的),那么我們就要連兩條邊,x->~yy->~x,至于為什么這么建圖,主要是從意義上考慮的,xy不能同時坐在對面,也就是說如果坐了x,那么對面就只能做~y,反過來也是一樣的,所以x->~y~y->x不是等價的。如果我們設新娘是0,新郎是1的話,同時需要連一條0->1的邊,表示對面只能坐新郎,因為如果0坐在對面,那么1也要坐在對面,顯然不符合邏輯。

②用tarjan算法(當然別的算法也可以,只不過我只會tarjan)求強連通分量。至于為什么有這一步,可以參考PPT《由對稱性解2-SAT問題》。

③判斷每個集合中的兩個元素是否在同一個強連通分量中。如果存在一個集合中的兩個元素在同一個強連通分量中,則無解,否則一定有解(至于為什么一定有解,可以參考PPT《由對稱性解2-SAT問題》)。

④依原來的有向邊,將縮后的點構造成反向圖并進行拓撲排序(便于后續的處理)。

⑤刪點并記錄方案。這個過程需要一個數組del[]表示縮后的點是否被刪去,然后依次遍歷每個強連通分量,如果del[]不為1,則把強連通分量里的值全部取出,在取出的x的同時,刪除~x所在的強連通分量以及該強連通分量的所有直接或間接的子節點。這樣的做的目的可以這么來理解,如果我們選擇了x,那么就不能選~x,所以凡是選了y就必須選~xy都要被刪去,又因為我們建的是反圖,所以要刪掉所有~x所在的強連通分量以及該強連通分量的所有直接或間接的子節點。

? ? ? ??⑥打印結果。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int n, m, N, G[1010][1010];
int col , a[1010][1010], num[1010], color[1010];
int g[1010][1010], dfn[1010], low[1010];
int s[1010], top, time, ins[1010];
int topo[1010], t, del[1010], vis[1010];
int ans[1010], res;
int cmp(const void *_p,const void *_q)
{
int *p=(int *)_p;
int *q=(int *)_q;
return *p-*q;
}
int init()
{
int i, j, k, n1, n2;
char b1,b2;
scanf("%d%d", &n, &m);
if(!n&&!m)
return 0;
N = 2 * n;
memset(G, 0, sizeof(G));
for(i = 0; i < m; i ++)
{
scanf("%d%c%d%c", &n1, &b1, &n2, &b2);
n1 = n1 * 2 + (b1 == 'h');
n2 = n2 * 2 + (b2 == 'h');
G[n1][n2 ^ 1] = 1;
G[n2][n1 ^ 1] = 1;
}
G[0][1] = 1;
return 1;
}
void tarjan(int u)
{
int i, j, v;
dfn[u] = low[u] = ++time;
for(v = 0; v < N; v ++)
if(G[u][v])
{
if(!dfn[v])
{
s[top ++] = v;
ins[v] = 1;
tarjan(v);
if(low[v] < low[u])
low[u] = low[v];
}
else if(ins[v] && dfn[v] < low[u])
low[u] = dfn[v];
}
if(low[u] == dfn[u])
{
for(i = 0, s[top] = -1; s[top] != u; i++)
{
top --;
a[col][i] = s[top];
color[s[top]] = col;
ins[s[top]] = 0;
}
num[col] = i;
col ++;
}
}
int judge()
{
int i;
for(i = 0;i < N; i ++)
if(color[i] == color[i ^ 1])
return 0;
return 1;
}
int dfs(int u)
{
int i, j, v;
vis[u] = -1;
for(v = 0; v < col; v ++)
if(g[u][v])
{
if(vis[v] == -1)
return 0;
if(!vis[v] && !dfs(v))
return 0;
}
vis[u] = 1;
topo[-- t] = u;
return 1;
}
int toposort()
{
int i, j, k;
t = col;
memset(vis, 0, sizeof(vis));
for(i = 0; i < col; i ++)
if(!vis[i] && !dfs(i))
return 0;
return 1;
}
void dfsdel(int u)
{
int v;
del[u] = 1;
for(v = 0; v < col; v ++)
if(g[u][v] && !del[v])
dfsdel(v);
}
void search(int i)
{
int j, p;
del[i] = 1;
for(j = 0; j < num[i]; j ++)
{
p = a[i][j];
ans[res ++] = p;
if(!del[color[p ^ 1]])
dfsdel(color[p ^ 1]);
}
}
int com()
{
int i, j, k, p, ok;
top = time = col = 0;
memset(ins, 0, sizeof(ins));
memset(dfn, 0, sizeof(dfn));
for(i = 0; i < N; i ++)
if(! dfn[i])
{
s[top ++] = i;
ins[i] = 1;
tarjan(i);
}
if(!judge())
return 0;
memset(g, 0, sizeof(g));
for(i=0;i<N;i++)
for(j=0;j<N;j++)
if(G[i][j] && color[i] != color[j])
g[color[j]][color[i]] = 1;
if(!toposort())
return 0;
memset(del , 0, sizeof(del));
res = 0;
for(i = 0; i < col; i ++)
if(!del[topo[i]])
search(topo[i]);
if(res != n)
return 0;
return 1;
}
void printpath()
{
int i, j, tt;
tt = 0;
qsort(ans, res, sizeof(ans[0]), cmp);
for(i = 1; i < res; i ++)
{
if(tt ++)
printf(" ");
printf("%d%c", ans[i] / 2, ans[i] % 2 == 0 ? 'h' : 'w');
}
printf("\n");
}
int main()
{
while(init())
{
if(com())
printpath();
else
printf("bad luck\n");
}
return 0;
}



轉載于:https://www.cnblogs.com/staginner/archive/2011/10/02/2198263.html

超強干貨來襲 云風專訪:近40年碼齡,通宵達旦的技術人生

總結

以上是生活随笔為你收集整理的POJ 3648 Wedding的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。