怕本身过久没写Tarjan了就会把这种神仙算法忘掉。算法
其实这种类型的图论题的套路仍是比较简单且显然的。网络
很显然的题目,由于在一个环(其实就是强连通份量)中的城市都只须要让其中一个知道就可让其它的城市都得知信息了。spa
所以咱们把在一个强连通份量中的点都缩点,而后就获得一个DAGcode
而后咱们只须要给入度为0的点传递信息便可string
CODEio
#include<cstdio> #include<cstring> using namespace std; const int N=100005; struct edge { int to,next; }e[N*5]; int head[N],col[N],ru[N],dfn[N],low[N],stack[N],n,m,x,y,cnt,tot,top,sum,ans; bool vis[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch=tc(); while (ch<'0'||ch>'9') ch=tc(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc(); } inline void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline void Tarjan(int now) { dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1; for (register int i=head[now];i^-1;i=e[i].next) if (!dfn[e[i].to]) { Tarjan(e[i].to); low[now]=min(low[now],low[e[i].to]); } else if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); if (!(low[now]^dfn[now])) { col[now]=++sum; vis[now]=0; while (stack[top]!=now) { col[stack[top]]=sum; vis[stack[top--]]=0; } --top; } } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); register int i,j; read(n); read(m); for (i=1;i<=m;++i) read(x),read(y),add(x,y); for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i); for (i=1;i<=n;++i) for (j=head[i];j^-1;j=e[j].next) if (col[i]^col[e[j].to]) ++ru[col[e[j].to]]; for (i=1;i<=sum;++i) if (!ru[i]) ++ans; printf("%d",ans); return 0; }
这个的话读一下题目就能够发现这是前一题的加权版。class
而后对于一个强连通份量中的点,在缩点后的权值应该是多少呢。next
很显然,确定找最便宜的人贿赂吗!static
因此咱们上一题的操做之上加权而后仍是找入度为0的点。top
不过注意下若是一个点的入度为0可是这个间谍没法被贿赂那么就没法被控制
CODE
#include<cstdio> #include<cstring> using namespace std; const int N=3005,M=8005; struct edge { int to,next; }e[M]; int head[N],col[N],ru[N],dfn[N],low[N],stack[N],a[N],s[N],num[N],n,m,x,y,cnt,tot,top,sum,ans,INF,p; bool vis[N]; inline char tc(void) { static char fl[100000],*A=fl,*B=fl; return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++; } inline void read(int &x) { x=0; char ch=tc(); while (ch<'0'||ch>'9') ch=tc(); while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=tc(); } inline void add(int x,int y) { e[++cnt].to=y; e[cnt].next=head[x]; head[x]=cnt; } inline int min(int a,int b) { return a<b?a:b; } inline void Tarjan(int now) { dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1; for (register int i=head[now];i^-1;i=e[i].next) if (!dfn[e[i].to]) { Tarjan(e[i].to); low[now]=min(low[now],low[e[i].to]); } else if (vis[e[i].to]) low[now]=min(low[now],dfn[e[i].to]); if (!(low[now]^dfn[now])) { col[now]=++sum; s[sum]=a[now]; num[sum]=now; vis[now]=0; while (stack[top]!=now) { col[stack[top]]=sum; vis[stack[top]]=0; s[sum]=min(s[sum],a[stack[top--]]); } --top; } } int main() { //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout); memset(head,-1,sizeof(head)); memset(e,-1,sizeof(e)); memset(a,127,sizeof(a)); INF=a[0]; register int i,j; read(n); read(p); for (i=1;i<=p;++i) read(x),read(y),a[x]=y; for (read(m),i=1;i<=m;++i) read(x),read(y),add(x,y); for (i=1;i<=n;++i) if (!dfn[i]) Tarjan(i); for (i=1;i<=n;++i) for (j=head[i];j^-1;j=e[j].next) if (col[i]^col[e[j].to]) ++ru[col[e[j].to]]; for (i=1;i<=sum;++i) if (!ru[i]) { if (!(s[i]^INF)) { printf("NO\n%d",num[i]); return 0; } ans+=s[i]; } printf("YES\n%d",ans); return 0; }