zoukankan      html  css  js  c++  java
  • P1262 间谍网络

    题目传送门

    描述:(给你一个有向图,其中某些点是可以买的,如果你买了一个点,)

    (你可以到达这个点指向的点,指向的这个点又能到它指向的点......(直到走不通),我们要选择一些点买,使图联通且代价最小!)

    算法:tarjan缩点

    思考过程

    选择哪一些点,能使图联通且代价最小呢?

    我们试着想一下,如果一个点被其他点指向,那我们最好选那个点

    如果那个点也被其他点指向,我们一直追溯过去,入度为0的点必须要选了

    但是如果存在环,那么没有点入度为0,这个时候就需要缩点,变成我们上面的那种情况

    缩点后环的代价就是环中点的最小代价

    问题又来了,如果环中没有点可以买怎么办??

    所以tarjan的时候只对那些可以买的点进行找环

    最后扫一遍,如果有点的dfn为0,说明没有遍历,即它是孤立的,没办法买到的,输出NO~

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=16009;
    const int inf=999999999;
    int n,m,q;
    struct p{
    	int to,nxt,w;
    }d[maxn];int head[maxn],cnt=1;
    void add(int u,int v,int w){
    	d[cnt].to=v,d[cnt].w=w,d[cnt].nxt=head[u],head[u]=cnt++;
    }
    int indug[maxn],monney[maxn],sumn[maxn];
    int low[maxn],dfn[maxn],stac[maxn],vis[maxn],top,id,sd[maxn],fen;
    void tarjan(int now)
    {
    	dfn[now]=low[now]=++id;
    	stac[++top]=now,vis[now]=1;
    	for(int i=head[now];i;i=d[i].nxt)
    	{
    		int v=d[i].to;
    		if(!dfn[v]){
    			tarjan(v);
    			low[now]=min(low[now],low[v]);
    		}
    		else if(vis[v])	low[now]=min(low[now],low[v]);
    	}
    	if(dfn[now]==low[now])
    	{
    		fen++;int temp;
    		while(temp=stac[top--])
    		{
    			vis[temp]=0;
    			sd[temp]=fen;
    			sumn[fen]=min(sumn[fen],monney[temp]);
    			if(temp==now)	break;
    		}
    	}
    }
    int main()
    {
    	cin>>n>>m;
    	for(int i=1;i<=n;i++)	monney[i]=sumn[i]=inf;
    	for(int i=1;i<=m;i++)
    	{
    		int l,r;cin>>l>>r;
    		indug[l]++;monney[l]=r;
    	}
    	cin>>q;
    	for(int i=1;i<=q;i++)
    	{
    		int l,r;cin>>l>>r;
    		add(l,r,0);indug[r]++;
    	}
    	for(int i=1;i<=n;i++)
    		if(indug[i]==0)
    		{
    			cout<<"NO"<<endl<<i;
    			return 0;
    		}
    	for(int i=1;i<=n;i++)//开始缩点
    	if(!dfn[i]&&monney[i]!=-1)	tarjan(i);
    	memset(indug,0,sizeof(indug));
    	for(int i=1;i<=n;i++)
    		for(int j=head[i];j;j=d[j].nxt)
    		{
    			int v=d[j].to;
    			if(sd[i]==sd[v])	continue;
    			indug[sd[v]]++;
    		}
    	int ans=0;
    	for(int i=1;i<=fen;i++)
    	if(!indug[i])	ans+=sumn[i];
    	cout<<"YES"<<endl<<ans;
    	return 0;
    }
    
  • 相关阅读:
    动态规划专题(二)——树形DP
    动态规划专题(一)——状压DP
    位运算相关(二)——位运算的简单变换操作
    位运算相关(一)——位运算学习笔记
    2018.10.05 TOPOI提高组模拟赛 解题报告
    【BZOJ1088】[SCOI2005] 扫雷Mine(分类讨论)
    【洛谷1273】有线电视网(树上背包)
    【洛谷2264】情书(字符串水题)
    【洛谷4287】[SHOI2011] 双倍回文(Manacher算法经典题)
    【洛谷2051】[AHOI2009] 中国象棋(烦人的动态规划)
  • 原文地址:https://www.cnblogs.com/iss-ue/p/12579837.html
Copyright © 2011-2022 走看看