• [COCI2011-2012#7] KAMPANJA


         神奇A题系列。。。。。。

         本来以为这个题是个 网络流 或者其他 神奇的多项式算法的题,于是就一直没有想出来。。。。。。

        然后再想想。。。边数点数同阶。都是不超过200的,,,说不定搜一搜剪剪枝就过了呢233333

        因为之前有了UVA12035那个题的多达接近十种剪枝的磨练(那些剪枝加起来想了几个月。。。。),所以对于本题的剪枝就是小菜一碟了23333

            第一个剪枝:首先只需要保留和1,2点同属于一个强连通分量的点(如果1和2不在同一强连通分量那么无解,但是本题好像并没有这样的数据),这个的话随便跑个tarjan就好了。

        

         然后可以发现,如果确定了1到2的路径的话,那么再从2到1就是一个点权是0或1的最短路问题了。出现在之前1到2路径上的点的点权是0,其他的点权是1。

        虽然点权不是都一样的,但是依然可以直接bfs出来,因为有0这个特殊的点权啊2333,一个双端队列就解决了。

        所以这一部分就直接降成O(1所在强连通分量的大小)。

            第二个剪枝:按理说我们是要搜出1到2的所有路径的,每搜到一条就bfs一遍更新答案。但是如果当前搜到一半的路径经过的点数 已经大于 之前的最小答案,直接剪掉(最优性剪枝)。

            一个奇奇怪怪不知道有没有用的剪枝:按理说我们应该是优先搜1到2经过点数少的路径,然后bfs。但是这样不一定是更优的,极有可能被卡(其实是我懒得预处理dist  23333),所以在搜路径的时候,我是random_shuffle的路径后继端点。

            这样做的好处是很快就能搜到一个正常的答案,不容易被数据卡,从而避免了很多不必要的搜索;坏处是搜到最后的答案是需要一定时间的(但从评测来看还好啦)

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    #define pb push_back
    const int maxn=205;
    stack<int> s;
    int H,T,q[maxn*23];
    int hd[maxn],ne[maxn],to[maxn],dc,lt[maxn];
    int num,n,m,d[maxn],dfn[maxn],low[maxn],k,ans=1<<30;
    inline void add(int x,int y){ to[++num]=y,ne[num]=hd[x],hd[x]=num;}
    bool v[maxn],can[maxn];
    
    void tarjan(int x){
    	dfn[x]=low[x]=++dc,s.push(x);
    	
    	for(int i=hd[x];i;i=ne[i])
    	    if(!dfn[to[i]]) tarjan(to[i]),low[x]=min(low[x],low[to[i]]);
    		else if(!lt[to[i]]) low[x]=min(low[x],dfn[to[i]]);
    	
    	if(low[x]==dfn[x]){
    		k++;
    		for(int c=s.top();;c=s.top()){
    			lt[c]=k,s.pop();
    			if(c==x) break;
    		} 
    	}
    }
    
    inline int calc(){
    	q[H=T=1000]=2,memset(d,-1,sizeof(d)),d[2]=0;
    	int x;
    	
    	while(H<=T){
    		x=q[H++];
    		for(int i=hd[x];i;i=ne[i]) if(can[to[i]]&&d[to[i]]<0){
    			if(v[to[i]]) d[to[i]]=d[x],q[--H]=to[i];
    			else d[to[i]]=d[x]+1,q[++T]=to[i];
    		}
    	}
    	
    	return d[1];
    }
    
    void dfs(int x,int y){
    	if(y>=ans) return;
    	if(x==2){ ans=min(ans,y+calc()); return;}
    	
    	vector<int> g;
    	for(int i=hd[x];i;i=ne[i]) if(can[to[i]]&&!v[to[i]]) g.pb(to[i]);
    	random_shuffle(g.begin(),g.end());
    	
    	for(int i=g.size()-1,o;i>=0;i--){
    		o=g[i],v[o]=1;
    		dfs(o,y+1),v[o]=0;
    	}
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	int uu,vv;
    	for(int i=1;i<=m;i++) scanf("%d%d",&uu,&vv),add(uu,vv);
    	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
    	
    	if(lt[1]!=lt[2]){ puts("-1"); return 0;}
    	
    	for(int i=1;i<=n;i++) if(lt[i]==lt[1]) can[i]=1;
    	
    	v[1]=1,dfs(1,1);
    	
    	cout<<ans<<endl;
    	return 0; 
    }
    

      

  • 相关阅读:
    「JSOI2015」套娃
    「JSOI2015」非诚勿扰
    「JSOI2015」送礼物
    「JSOI2015」子集选取
    「JSOI2015」salesman
    「JSOI2015」字符串树
    [2]树的DFS序
    hdu 6058 Kanade's sum
    UVALive 6907 Body Building
    CF617/E XOR and Favorite Number
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9055613.html
Copyright © 2020-2023  润新知