LOJ-10095(缩点的特殊使用)

时间:2022-09-23 18:43:26

题目链接:传送门

思路:

缩点求最值,但是有一点行不通,如果被选中的点才能缩点,否则缩点没有意义;

所以就先缩选中的点,然后从小到大统计没有缩点的点,就是NO;

如果找最小值,就是一个环里的最小值,然后求和就好了。

注意:

(1)预处理si和mon

(2)对选中的点缩点,不然全部缩点后比较麻烦

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = ;
const int INF = ;
int head[maxn],next[maxn],ver[maxn],tot;
int num[maxn],low[maxn],co[maxn],tim,col,si[maxn];
int st[maxn],top;
int mon[maxn],in[maxn];
int MIN(int x,int y)
{
return x<y?x:y;
}
void Init()
{
for(int i=;i<maxn;i++) si[i]=INF,mon[i]=INF;
tot=;col=;tim=;top=;
}
void addedge(int u,int v)
{
ver[++tot]=v;next[tot]=head[u];head[u]=tot;
}
void Tarjan(int u)
{
int i,v;
low[u]=num[u]=++tim;
st[++top]=u;
for(i=head[u];i;i=next[i]){
v=ver[i];
if(!num[v]){
Tarjan(v);
low[u]=MIN(low[u],low[v]);
}
else if(!co[v]) low[u]=MIN(low[u],num[v]);
}
if(low[u]==num[u]){
col++;
co[u]=col;
si[col]=mon[u];
while(st[top]!=u){
si[col]=MIN(si[col],mon[st[top]]);
co[st[top]]=col;
top--;
}
top--;
}
}
int main(void)
{
int i,j,x,y,n,pp,rr;
scanf("%d%d",&n,&pp);
Init();
for(i=;i<=pp;i++){
scanf("%d%d",&x,&y);
mon[x]=y;
}
scanf("%d",&rr);
for(i=;i<=rr;i++){
scanf("%d%d",&x,&y);
addedge(x,y);
} for(i=;i<=n;i++)
if(!num[i]&&mon[i]!=INF) Tarjan(i); for(i=;i<=n;i++)
if(!num[i]){
printf("NO\n%d",i);
return ;
}
for(i=;i<=n;i++){
for(j=head[i];j;j=next[j]){
if(co[i]!=co[ver[j]]){
in[co[ver[j]]]++;
}
}
} int ans=;
for(i=;i<=col;i++)
if(in[i]==) ans+=si[i];
printf("YES\n%d",ans);
return ;
}