洛谷——P1262 間諜網絡
P1262 間諜網絡
題目描述
由於外國間諜的大量滲入,國家安全正處於高度的危機之中。如果A間諜手中掌握著關於B間諜的犯罪證據,則稱A可以揭發B。有些間諜收受賄賂,只要給他們一定數量的美元,他們就願意交出手中掌握的全部情報。所以,如果我們能夠收買一些間諜的話,我們就可能控制間諜網中的每一分子。因為一旦我們逮捕了一個間諜,他手中掌握的情報都將歸我們所有,這樣就有可能逮捕新的間諜,掌握新的情報。
我們的反間諜機關提供了一份資料,色括所有已知的受賄的間諜,以及他們願意收受的具體數額。同時我們還知道哪些間諜手中具體掌握了哪些間諜的資料。假設總共有n個間諜(n不超過3000),每個間諜分別用1到3000的整數來標識。
請根據這份資料,判斷我們是否有可能控制全部的間諜,如果可以,求出我們所需要支付的最少資金。否則,輸出不能被控制的一個間諜。
輸入輸出格式
輸入格式:
第一行只有一個整數n。
第二行是整數p。表示願意被收買的人數,1≤p≤n。
接下來的p行,每行有兩個整數,第一個數是一個願意被收買的間諜的編號,第二個數表示他將會被收買的數額。這個數額不超過20000。
緊跟著一行只有一個整數r,1≤r≤8000。然後r行,每行兩個正整數,表示數對(A, B),A間諜掌握B間諜的證據。
輸出格式:
如果可以控制所有間諜,第一行輸出YES,並在第二行輸出所需要支付的賄金最小值。否則輸出NO,並在第二行輸出不能控制的間諜中,編號最小的間諜編號。
輸入輸出樣例
輸入樣例#1:【樣例1】 3 2 1 10 2 100 2 1 3 2 3 【樣例2】 4 2 1 100 4 200 2 1 2 3 4輸出樣例#1:
【樣例1】 YES 110 【樣例2】 NO 3
錯誤搜索 68、、、(數據太水??!!)
思路: 我們將可以收買的間諜按價格進行排序,然後在按價格挨個更新我們能通過該間諜可以得到的間諜信息,ans+=該間諜的價格。 然後將所有的間諜買通以後,判斷不能得到的間諜的信息。要求最小,那麽我們用一個vist數組來記錄該點的信息是否可以被得知,如果不能被得知,輸出no以及當前點的編號 #include68分錯誤的思路、、、<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 21000 using namespace std; bool vis[N],vist[N]; int n,m,r,x,y,ans,tot,head[N]; 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; } struct A { int x,c; }a[N]; struct Edge { int to,next,from; }edge[N]; int add(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot; } int cmp(A x,A y) { return x.c<y.c; } int dfs(int x) { vis[x]=true;vist[x]=true; for(int i=head[x];i;i=edge[i].next) { int t=edge[i].to; if(!vis[t]) dfs(t); } vis[x]; } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) a[i].x=read(),a[i].c=read(); sort(a+1,a+1+m,cmp); r=read(); while(r--) x=read(),y=read(),add(x,y); for(int i=1;i<=m;i++) if(!vist[a[i].x]) dfs(a[i].x),ans+=a[i].c; for(int i=1;i<=n;i++) if(!vist[i]) { printf("NO\n%d",i); return 0;} printf("YES\n%d",ans); return 0; }
但是這樣搜索是有bag的,為什麽??
我們先對於間諜編號進行排序,然後再看他是否對其他間諜有貢獻,如果有就果斷的收買這個間諜,但是如果我們後面有一個間諜必須要被收買,但是收買了這個間諜以後我們之前收賣的一個間諜的信息可以通過這個間諜直接得到,那樣的話,我們完全就可以不收買上一個間諜。
既然這樣,我們怎麽搜??
我們用一個did數組來記錄一個點被訪問過幾次,也就是說我們在後面收買一個必須被收買的間諜時,我們是否可以將這裏面的所有信息全部得到,我們是否可以不再收買這個間諜。(可能說的有點含糊,我們來看一下代碼吧)
#include<cstdio> #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define N 51000 using namespace std; int n,m,r,x,y,tot,ans,f[N],head[N],did[N]; struct A { int x,c; }a[N]; struct Edge { int to,from,next; }edge[11000]; 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; } int add(int x,int y) { tot++; edge[tot].to=y; edge[tot].next=head[x]; head[x]=tot; } int cmp(A a,A b) { return a.c<b.c; } int dfs(int x,int fa) { if(f[x]) did[f[x]]--; f[x]=fa; did[fa]++; for(int i=head[x];i;i=edge[i].next) if(f[edge[i].to]!=fa) dfs(edge[i].to,fa); } int main() { n=read(),m=read(); for(int i=1;i<=m;i++) a[i].x=read(),a[i].c=read(); sort(a+1,a+1+m,cmp);r=read(); while(r--) x=read(),y=read(),add(x,y); for(int i=1;i<=m;i++) if(f[a[i].x]) { for(int j=head[a[i].x];j;j=edge[j].next) if(!f[edge[j].to]) {dfs(a[i].x,i); break;} } else dfs(a[i].x,i); for(int i=1;i<=n;i++) if(!f[i]) { printf("NO\n%d\n",i); return 0; } for(int i=1;i<=m;i++) if(did[i]) ans+=a[i].c; printf("YES\n%d\n",ans); return 0; }
洛谷——P1262 間諜網絡