• P6134[JSOI2015]最小表示【bitset,拓扑排序】


    正题

    题目链接:https://www.luogu.com.cn/problem/P6134


    题目大意

    给出一张\(n\)个点\(m\)条边的\(DAG\)。求联通情况不变的情况下最多删除几条边。

    \(1\leq n\leq 3\times 10^4,0\leq M\leq 10^5\)


    解题思路

    拓扑排序后,如果确定了后面若干个的最优解,那么不会影响到前面的决策,我们只需要对于每个点考虑删除最多的出边即可。

    从后往前枚举,对于一个点连接的集合\(E\),按照拓扑序从小到大排后,每次加入一个点和它所有连接的点,如果该点已经联通,那么这条边就可以删除了。

    \(bitset\)可以快速实现这个过程。

    时间复杂度\(O(\frac{mn}{w})\)


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<bitset>
    #include<queue>
    #include<vector>
    using namespace std;
    const int N=3e4+10;
    int n,m,cnt,tot,ans;
    int in[N],ls[N],top[N],tfn[N];
    queue<int> q;vector<int> v;
    bitset<N> b[N];
    struct node{
    	int to,next;
    }a[N<<2];
    void addl(int x,int y){
    	a[++tot].to=y;
    	a[tot].next=ls[x];
    	ls[x]=tot;return;
    }
    void topsort(){
    	for(int i=1;i<=n;i++)
    		if(!in[i])q.push(i);
    	while(!q.empty()){
    		int x=q.front();q.pop();
    		top[++cnt]=x;tfn[x]=cnt;
    		for(int i=ls[x];i;i=a[i].next){
    			int y=a[i].to;
    			in[y]--;
    			if(!in[y])q.push(y);
    		}
    	}
    	return;
    }
    bool cmp(int x,int y)
    {return tfn[x]<tfn[y];}
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=m;i++){
    		int x,y;
    		scanf("%d%d",&x,&y);
    		addl(x,y);in[y]++;
    	}
    	topsort();
    	for(int p=n;p>=1;p--){
    		int x=top[p];v.clear();b[x][x]=1;
    		for(int i=ls[x];i;i=a[i].next)
    			v.push_back(a[i].to);
    		sort(v.begin(),v.end(),cmp);
    		for(int i=0;i<v.size();i++){
    			int y=v[i];
    			if(b[x][y]) ans++;
    			else b[x]|=b[y];
    		}
    	}
    	printf("%d\n",ans);
    }
    
  • 相关阅读:
    Grovvy初识
    在eclipse中安装插件
    解决 APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tas
    Axis2 webservice入门--Webservice的发布与调用
    一步一步教你自定义博客园(cnblog)界面
    Enum枚举
    并行与并发
    多线程join(加入)
    守护线程
    停止线程
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14402284.html
Copyright © 2020-2023  润新知