GSA:2020 年全球頻譜拍賣價值 275 億美元
阿新 • • 發佈:2021-02-08
文章目錄
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 p≤n≤3×103,m≤8000
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);
}