1. 程式人生 > 資訊 >GSA:2020 年全球頻譜拍賣價值 275 億美元

GSA:2020 年全球頻譜拍賣價值 275 億美元

文章目錄

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

https://www.luogu.com.cn/problem/P1262


D e s c r i p t i o n Description
Description

n n n個間諜,其中有 p p p個願意被收買,有 m m m條關係,表示收買了 x x x就能無償收買 y y y,且該關係可以傳遞

問是否能收買所有人以及對應的最小花費
如果不行,還得輸出不能收買的人的最小編號

資料範圍: p ≤ n ≤ 3 × 1 0 3 , m ≤ 8000 p\leq n\leq 3\times 10^3,m\leq 8000 pn3×103,m8000


S o l u t i o n Solution Solution

顯然我們定義無法收買的人收買的代價為無窮大

一個強聯通分量顯然要麼收買裡面可以收買的最小值,要麼收買指向它的點或者連通分量

所以我們可以縮點,縮點後的權值即為該連通分量的權值的最小值

能收買所有人當且僅當所有入度為0的點都是可以收買的

如果有解,輸出這些點的和就好了

無解的話則需另行判斷

我的方法是先把可以直接收買的點拎出來,跑一遍 d f s dfs dfs標記哪些點是可以被收買的(間接),更改它們的權值

然後再把無法標記的點拎出來,再跑一遍 d f s dfs dfs求出最小編號(注意這次的 d f s dfs dfs只能走無法收買的點的邊,如果遇到能收買的點就不能繼續走下去了)即可

時間複雜度: O ( n + m ) O(n+m) O(n+m)


C o d e Code Code

#include<cstdio>
#include<cctype> #include<cstring> #include<algorithm> #define LL long long #define N 3010 #define M 5000010 using namespace std;int l[N],tot; struct node{int next,to;}e[M]; inline void add(int u,int v){e[++tot]=(node){l[u],v};l[u]=tot;return;} inline LL read() { char c;LL d=1,f=0; while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48; while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48; return d*f; } int dfn[N],low[N],stk[N],top,cnt,which[N],siz[N],rd[N],cd[N],val[N],minn[N]; bool vis[N]; inline void Tarjan(int x) { dfn[x]=low[x]=++cnt;vis[x]=true;stk[++top]=x; for(register int i=l[x];i;i=e[i].next) { int y=e[i].to; if(dfn[y]==0) { Tarjan(y); low[x]=min(low[x],low[y]); } else if(vis[y]) low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { int y; while(y=stk[top--]) { siz[x]++;val[x]=min(val[x],val[y]);minn[x]=min(minn[x],minn[y]); which[y]=x;vis[y]=false; if(y==x) break; } } } int n,p,x,y,m,ans; bool bj[N],flg; #include<vector> vector<int>g[N]; inline void dfs(int x) { for(register int i=0;i<g[x].size();i++) if(val[g[x][i]]==0x3f3f3f3f) { dfs(g[x][i]); minn[x]=min(minn[x],minn[g[x][i]]); } return; } bool bj2[N]; inline void dfs2(int x) { for(register int i=0;i<g[x].size();i++) { val[g[x][i]]=0; dfs2(g[x][i]); } return; } signed main() { memset(val,0x3f,sizeof val); n=read();p=read(); for(register int i=1;i<=n;i++) minn[i]=i; for(register int i=1;i<=p;i++) x=read(),y=read(),val[x]=y,minn[x]=0x3f3f3f3f; m=read(); for(register int i=1;i<=m;i++) x=read(),y=read(),add(x,y); for(register int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); for(register int i=1;i<=n;i++) for(register int j=l[i];j;j=e[j].next) if(which[i]!=which[e[j].to]) rd[which[e[j].to]]++,cd[which[i]]++,g[which[i]].push_back(which[e[j].to]); for(register int i=1;i<=n;i++) if(which[i]==i&&rd[i]==0) { if(val[i]==0x3f3f3f3f) {bj[i]=true;flg=true;continue;} ans+=val[i];bj2[i]=true; } if(!flg) return printf("YES\n%d",ans)&0; for(register int i=1;i<=n;i++) if(bj2[i]) dfs2(i); for(register int i=1;i<=n;i++) if(bj[i]) dfs(i); ans=0x3f3f3f3f; for(register int i=1;i<=n;i++) if(bj[i]) ans=min(ans,minn[i]); printf("NO\n%d",ans); }