zoukankan      html  css  js  c++  java
  • 【题解】 Knots UVA

    看到了一道不一样的题
    一道关于“解结”的题
    真的是没有思路,连题都看不懂
    然后抄别人的代码,看别人的题解
    大体框架是把输入的P个上下压在一起的数对给消去,最终变成一个简简单单的圈圈
    别人的题解:

    Ideas: 一个比较简单的想法是,我们模拟人解绳子的过程。具体怎么解呢?

    1. 如果我们发现,通过平移某一段绳子可以使交点个数减少,那么我们就这么操作。
    2. 如果我们发现,通过翻转某一段绳子可以使交点个数减少,那么我们就这么操作。

    仔细想想,在人解绳子的过程中,貌似再没有任何其它高级的操作,因此我们可以认为以上两种操作可以解开任何可以解开的绳子。同时,题目中也说,任何一个合法绳环都可以这样生成。

    对于第一个操作,我们可以这样判定:如果存在两段绳子 a,b
    ,a完全在 b的上方,并且两段绳子都从交点 A开始,到交点 B结束,不经过其它任何交点。那么我们可以直接删除这两个交点,因为通过平移 a,b

    ,这两个交点可以消失。

    对于第二个操作,如果有一段绳子的左右端点重合于交点 A
    ,且不经过任何其它交点,我们可以删除交点 A,因为我们可以通过翻转这一段绳子使这个交点消失。

    -end-

    总结:平移和旋转

    别人的题解2:

    先用链表把每一个节点串起来,并对有覆盖的地方进行标记。

    模拟解锁操作,如果一个节点和它所覆盖的节点之间没有其他结,那么进行逆self loop操作。

    同理进行逆passing操作。

    如果能把所有的结都解开,则答案是有解。

    优化:把没有覆盖/被覆盖的节点提前删掉,缩短链表长度。

    -end-

    抄的别人的代码:

    
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <string>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    
    using namespace std;
    
    struct node{
    	int pre, nxt;
    }a[1000010];
    int link[1000010], ud[1000010], L, P;
    void Del(int x){
    	ud[x]=0;
    	a[a[x].pre].nxt = a[x].nxt;
    	a[a[x].nxt].pre = a[x].pre;
    }
    int T;
    int main()
    {
    	cin >> T;
    	int T0= T;
    	while(T--){
    		memset(link,0,sizeof(link));
    		memset(ud,0,sizeof(ud));
    		cin>>L>>P;
    		for(int i=0;i<L;i++){
    			a[i].pre = i-1;
    			a[i].nxt = i+1;
    		}
    		a[0].pre = L-1;
    		a[L-1].nxt = 0;
    		int u, v;
    		for(int i=1;i<=P;i++){
    			cin>>u>>v;
    			link[u]=v;link[v]=u;
    			ud[u]=1;ud[v]=-1;//上 下
    			 
    		}
    		for(int i=0;i<L;i++)
    			if(!ud[i])	Del(i);
    		int hd=0;
    		while(P){//对每一个压迫的数对处理 
    			bool flag=1;//不能删 
    			while(!ud[hd])	hd++;
    			for(int i=a[hd].nxt;i!=hd&&flag;i=a[i].nxt ){//每个数对都要处理一圈 
    			//扫描一圈                  
    				int u=i,v=a[i].nxt;//接下来我们的操作针对的是前后相连的两个点 
    				
    				if(ud[u]==ud[v] && (a[link[u]].nxt == link[v] || a[link[v]].nxt == link[u]))//???
    				{//uv要在同一平面上    我(u)所压的那个点的前后相连的点是我旁边这个点v所压的点 ||  当我是v时如果可以的话
    				//这就是传说中的平移 
    					Del(u);Del(v);
    					Del(link[u]);Del(link[v]);
    					//删了这4个点 
    					P-=2;//减少2对 
    					flag=0;//能删了 
    				}//passing
    				
    				else if(link[v]==u || link[u]==v){
    				//上下遮挡 
    				//这就是传说中的旋转 
    					Del(u);Del(v);
    					// 删了这两个点 
    					P--;//减少1对 
    					flag=0;//能删了 
    				}//self loop
    				
    			}
    			
    			if(flag)	break;//不行 
    		}
    		printf("Case #%d: ",T-T0);
    		if(!P)	printf("YES
    ");//所有的压迫都被打开了 
    		else printf("NO
    ");
    	}
    	return 0;
    }
    
    
    

    不过我至少懂了,而且注释是我自己写的

  • 相关阅读:
    最新版 VS2015|Visual Studio Enterprise 2015简体中文版(企业版)
    MY97 日期控件只输入今天之前的值
    VARIANT类型
    C++ Struct
    MFC网络编程
    套接字编程(VC_Win32)
    套接字相关函数
    网络编程
    char str[] 与 char *str的区别详细解析
    Windows下C++多线程同步与互斥简单运用
  • 原文地址:https://www.cnblogs.com/ZhengkunJia/p/12906096.html
Copyright © 2011-2022 走看看