1. 程式人生 > >uoj 175. 新年的網警

uoj 175. 新年的網警

題意:

在這新年的第一天,猴族首領猴腮雷打算來整治一下網路風氣。這時,他聽說在一個叫做 Universal OJ 使用者群 的 QQ 群中有人在散播(開)謠言(車),於是他就派了一群網警把這個使用者群裡的人都抓了回來,試圖找到謠言的源頭。
這個使用者群中有 nn 個人,這些人中存在 mm 對雙向的直接認識關係,這個社交網路中任意兩個人都是直接或者間接認識的。經過研究,謠言的散播以如下的方式進行:
首先在某個時刻 TT,謠言的源頭想出了一個謠言,於是他在時刻 T+1T+1 把這個謠言講給了所有和他直接認識的人聽。
如果一個人在第 ii 個時刻第一次聽到了這個謠言,他會在第 i+1i+1 時刻時把這個謠言講給所有和他直接認識的人聽。
現在網警們問出來每一個人第一次聽到這個謠言的時間,但是遺憾的是他們並不知道 TT 的具體數值。而且,謠言的發起者不會坐以待斃,他可以隨便回答一個時間(當然也可以回答真實時間),而其他不是謠言的源頭的人一定不會撒謊。(注意:網警知道謠言的發起者可以說謊)
猴族首領猴腮雷根據網警們遞交上來的口供,非常輕易的就推理出了謠言的源頭是誰並把他繩之以法。但是他發現,有些情況下,根據口供還不能唯一確定嫌疑人(即嫌疑人可能有多個),於是他想要知道哪些人是“安全的謠言發起人”。
一個人是安全的謠言發起人,當且僅當他可以通過捏造口供使得猴腮雷無法唯一確定嫌疑人(具體可以看樣例解釋)。

題解:

%%%羊老師教我做題。
等於是問是否有另一個點到各點距離和當前點一樣。
顯然,這個點的距離不能超過2。然後容易想到這兩個點的連邊情況要完全一樣(忽略他們相互連邊)。
然後就完了嗎?偷看題解,發現還有兩種情況:
1、度數為1的點。
2、連向度數為1的點的點。
容易證明
然後hash判邊是否相同。
code:

#include<map>
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cstring>
#define LL unsigned long long
using namespace std; const LL base=10037; map <LL,int> mp; LL pre[100010],hash[100010]; int n,m,d[100010],ans[100010]; struct node{ int y,next; }a[400010];int len,last[100010]; inline void write(int x) { if (!x) return (void)puts("0"); if (x < 0) putchar('-'), x = -x; static short s[12], t; while (x) s[++t] = x % 10
, x /= 10; while (t) putchar('0' + s[t--]); } int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void ins(int x,int y) { a[++len].y=y; a[len].next=last[x];last[x]=len; } int main() { int T;T=read(); pre[0]=1;for(int i=1;i<=100000;i++) pre[i]=pre[i-1]*base; while(T--) { n=read();m=read(); for(int i=1;i<=n;i++) hash[i]=0; len=0;memset(last,0,sizeof(last)); memset(d,0,sizeof(d));mp.clear(); for(int i=1;i<=m;i++) { int x,y;x=read();y=read(); d[x]++;d[y]++;hash[x]+=pre[y];hash[y]+=pre[x]; ins(x,y);ins(y,x); } memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++) mp[hash[i]]++; int k=0; for(int x=1;x<=n;x++) { if(d[x]==1||mp[hash[x]]>1) k++,ans[x]=1; else { bool flag=false; for(int i=last[x];i;i=a[i].next) { int y=a[i].y; if(d[y]==1) {flag=true;break;} } if(flag) k++,ans[x]=1; } } mp.clear(); for(int i=1;i<=n;i++) hash[i]+=pre[i],mp[hash[i]]++; for(int i=1;i<=n;i++) if(ans[i]==0&&mp[hash[i]]>1) k++,ans[i]=1; write(k);putchar('\n'); for(int i=1;i<=n;i++) if(ans[i]) write(i),putchar(' '); putchar('\n'); } }