zoukankan      html  css  js  c++  java
  • USACO 1.3... 虫洞 解题报告(搜索+强大剪枝+模拟)

    这题可真是又让我找到了八数码的感觉。。。哈哈。
       首先,第一次见题,没有思路,第二次看题,感觉是搜索,就这样写下来了。
       这题我几乎是一个点一个点改对的(至于为什么是这样,后面给你看一个神奇的东西),让我发现了许多搜索上的问题。思路非常简
    单:搜索出每一种可能的配对方式,然后从每一个点出发
    一遍,模拟走的过程,如果到死循环里面就答案加一,那个模拟走的过程话说我敲的还是很爽的,这题难在对配对序列的搜索和配对状态重
    复的剪枝上面。
       记得配对序列的搜索我敲了5、6个版本,发现AC之后一个都没有用上,但是在这个过程中,你脑袋里面模拟那个搜索的过程的确是很爽
    啊,确定了搜索序列的方法之后,就分别对每一个序列执行模拟走的操作,但是,这是一个严重的问题出现了,大量的重叠状态,导致所有
    N = 12的数据严重超时,让人更加不理解的是,USACO上原题还有小于12的数呢,但是COGS上的数据好像全部都是12,坑了。但是,剪
    枝的方法十分的妙,什么,单调。我给出一个不重复的序列作为说明:
    当N等于6时,所有可能的序列如下:
    12 34 56 | 12 35 46 | 12 36 45 | 
    13 24 56 | 13 25 46 | 13 26 45 |
    14 23 56 | 14 25 36 | 14 26 35 |
    15 23 46 | 15 24 36 | 15 26 34 |
    16 24 35 | 16 23 45 | 16 25 34 |
    我们可能清楚的发现,如果你的搜索顺序对的话,那么有一个神奇而又能让你通过测试的性质,就是这个序列无论什么样子,他的奇数位上
    的数字都是单调递增的,正是因为这个东西,让我剪掉了数量非常大的无用状态。
    至于怎么体现这句话,关键地方说完了,直接贴代码,自己看吧。。。有许多大神0.0几秒就过了,不能理解,我的0.6几秒,这效率,天
    差地
    别啊,,,自愧不如。。。。。
    Code:
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <map>
    using namespace std;
    
    int N;
    int Ans = 0;
    bool vi[15];
    bool a[15][15];
    int que[15];
    struct data{
    	int x,y;
    }G[15];
    
    int T[30];
    int tot = 0;
    
    void dfs(int,int,int);
    bool cmp(data,data);
    bool judge();
    bool go(int,int);
    void outandin();
    
    int main(){
    	freopen("wormhole.in","r",stdin);
    	freopen("wormhole.out","w",stdout);
    	scanf("%d",&N);
    	for(int i = 1;i <= N;++ i){
    		scanf("%d%d",&G[i].x,&G[i].y);
    		T[++ tot] = G[i].x;
    		T[++ tot] = G[i].y;
    	}
    	outandin();
    	sort(G+1,G+N+1,cmp);
    	
    	for(int i = 2;i <= N;++ i){
    		dfs(1,i,2);
    	}
    	printf("%d
    ",Ans);
    	return 0;
    }
    
    void dfs(int now,int next,int depth){
    	vi[now] = vi[next] = true;
    	que[depth] = now;que[depth+1] = next;
    	if(depth == N && N%2==0){
    		if(judge())
    			++ Ans;
    		return;
    	}
    	else if(depth == N-1 && N%2 == 1){
    		if(judge())
    			++ Ans;
    		return;
    	}
    	
    	for(int i = 1;i <= N;++ i){
    		if(!vi[i] && i > now){//这括号里面很神奇的一句。。。i > now 剪枝的神器。。
    			for(int j = 1;j <= N;++ j){
    				if(!vi[j] && j != i && j > i){
    					dfs(i,j,depth+2);
    					vi[j] = false;
    				}
    			}
    			vi[i] = false;
    		}
    	}
    	vi[now] = vi[next] = false;
    }
    
    
    bool cmp(data a,data b){
    	if(a.x == b.x)
    	    return a.y < b.y;
    	return a.x < b.x;
    }
    
    bool judge(){
    	for(int i = 2;i <= (N&1?N:N+1);++ i)
    	    if(go(que[i],i))
    	        return true;
    	return false;
    }
    
    bool go(int now,int pos){
    	bool v[15];
    	memset(v,false,sizeof v);
    	
    	while(1){
    		if(v[now])
    		    return true;
    		v[now] = true;
    		pos = ((pos&1) ? (pos-1):(pos+1));
    		bool flag = false;
    		for(int i = 1;i <= N;++ i){
    			int n = que[pos];
    			if(i != n && G[i].x > G[n].x && G[i].y == G[n].y){
    				for(int j = 2;j <= (N&1?N:N+1);++ j){
    					if(que[j] == i){
    						now = que[j];
    						pos = j;
    						flag = true;
    						break;
    					}
    				}
    			}
    			if(flag)
    			    break;
    		}
    		if(!flag)
    		    return false;
    	}
    }
    
    map <int,int> pos;
    map <int,bool> fla;
    void outandin(){
    	int no = 0;
    	for(int i = 1;i <= tot;++ i){
    		if(!fla[T[i]]){
    			fla[T[i]] = true;
    			pos[T[i]] = ++ no;
    		}
    	}
    	for(int i = 1;i <= N;++ i){
    		G[i].x = pos[G[i].x];
    		G[i].y = pos[G[i].y];
    	}
    }
    
    
    如果你不剪枝,但是时间又特别特别长的话(也就是没有超时这种东西),你的输出就要这样写:
            if(N > 11)
    	    printf("%d
    ",Ans/120);
    	else if(N > 9)
    	    printf("%d
    ",Ans/24);
    	else if(N > 7)
    	    printf("%d
    ",Ans/6);
    	else if(N > 5)
    	    printf("%d
    ",Ans/2);
    	else
    	    printf("%d
    ",Ans);
    正是这个让我一个点一个点的过,也是这个让我发现了大量的重复状态,由那个/120你就知道重复状态有多么可怕了。。。。。
    总之,模拟走的过程练码力,搜索的过程练搜索。。一道非常不错的题目。。。
  • 相关阅读:
    minikube国内在线部署体验
    分表与分库使用场景以及设计方式
    epool与select有什么区别
    使用ssh-keygen生成私钥和公钥
    mysql关键字冲突
    MySQL 获取当前时间戳
    平时常说的ThreadLocal,今天就彻底解决它
    mysql和mssql最大连接数
    Spring Boot实战:拦截器与过滤器
    Mysql 索引问题-日期索引使用
  • 原文地址:https://www.cnblogs.com/sxprovence/p/4705070.html
Copyright © 2011-2022 走看看