LOJ-10095(缩点的特殊使用)
题目链接:传送门
思路:
缩点求最值,但是有一点行不通,如果被选中的点才能缩点,否则缩点没有意义;
所以就先缩选中的点,然后从小到大统计没有缩点的点,就是NO;
如果找最小值,就是一个环里的最小值,然后求和就好了。
注意:
(1)预处理si和mon
(2)对选中的点缩点,不然全部缩点后比较麻烦
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 500100; const int INF = 99999999; 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=0;i<maxn;i++) si[i]=INF,mon[i]=INF; tot=0;col=0;tim=0;top=0; } 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=1;i<=pp;i++){ scanf("%d%d",&x,&y); mon[x]=y; } scanf("%d",&rr); for(i=1;i<=rr;i++){ scanf("%d%d",&x,&y); addedge(x,y); } for(i=1;i<=n;i++) if(!num[i]&&mon[i]!=INF) Tarjan(i); for(i=1;i<=n;i++) if(!num[i]){ printf("NO\n%d",i); return 0; } for(i=1;i<=n;i++){ for(j=head[i];j;j=next[j]){ if(co[i]!=co[ver[j]]){ in[co[ver[j]]]++; } } } int ans=0; for(i=1;i<=col;i++) if(in[i]==0) ans+=si[i]; printf("YES\n%d",ans); return 0; }