zoukankan      html  css  js  c++  java
  • pku3715 Blue and Red

    快顶不住了,理解了多少,先写出来再说;

    题意:

    军队里面要展开实战演练,已经将n个士兵分成了两队,红队和蓝队。指挥官认为,如果两个属于不同阵营中的士兵是好朋友,那么演练就会有感情因素的干扰。所以要选出最少的人,以排除感情因素的干扰。问要选出多少人?选哪些人?

    分析: 就题目而已,很明显是一道求最小覆盖点集的题目,又最小覆盖点数==最大匹配数,所以,单求出队人数的话,就是一道完完全全的求二分最大匹配的题目,可是,要怎么求出最小覆盖点集呢?而且还要按字典序输出?问题就在这里了,在求出最大匹配数的基础,从第一个点开始枚举,若去掉这个点,此时,最小覆盖数减少(即从该点匹配的点为起点,找不到增广路径),则该点属于最小覆盖点集,应该输出,且去掉,否则,恢复该点,继续枚举;

    因为从第一个点开始枚举,所以保证了字典序输出。

    整个算法的过程还不算是理解了,因为有一个坎一直过不去,是我对寻找增广路径的过程还理解的不够透彻吗?当然枚举到一个点时,匹配的点已经删掉了,这时候若调用深搜,返回值肯定为假,即找不到增广路,这时候该点不是要输出了吗?可是有没有加一个判断都过了,是代码在处理的时候已经考虑了这种情况了吗?还是根本不会出现这种情况?求大牛解释

    #include<iostream>
    using namespace std;
    int wet[205][205];
    int mx[205], my[205]; 
    char vstd[205]; 
    char del[205]; //是否属于最小点覆盖集
    int grp[205]; //0, 1
    int nv, ne;
    int pathx(int x) 
    {
        int y; 
        if(del[x]) return 0; //如果该点属于最小点覆盖集,就不用再找了.     
        for(y = 1; y <= nv; y++)
        {
              if(wet[x][y] && !vstd[y] && !del[y])
              {
                           vstd[y] = 1;
                           if(my[y]==-1 || pathx(my[y]))
                           {
                                        my[y] = x;
                                        mx[x] = y;
                                        return 1;
                           }
              }
        }
        return 0;
    }
    int pathy(int y)
    {
        int x; 
        if(del[y]) return 0; 
        for(x = 1; x <= nv; x++)
        {
             if(wet[x][y] && !vstd[x] && !del[x])
             {
                          vstd[x] = 1;
                          if(mx[x]==-1 || pathy(mx[x]))
                          {
                                       my[y] = x;
                                       mx[x] = y;
                                       return 1;
                          }
             } 
        }
        return 0;
    }
    void MaxMatch()
    {
         int i, x, y, res = 0;  
         memset(del, 0, sizeof(del));
         memset(mx, -1, sizeof(mx));
         memset(my, -1, sizeof(my));
         for(x = 1; x <= nv; x++)
         {
               memset(vstd, 0, sizeof(vstd));
               res += pathx(x);
         }
         printf("%d", res);
         for(i = 1; i <= nv; i++)
         {
               if(grp[i]==0)  //如果是X[]的点 
               {
                            y = mx[i];
                            if(y==-1)
    						continue;                       
                            mx[i] = -1;  //去掉这条最大匹配边,寻找完后不用加回来,为什么? 
                            my[y] = -1;
    					//	if(del[y]) continue; 个人觉得这里应该判断一下的,可是不判断也一样过
                            del[i] = 1;  //假设它是最小点覆盖集中一点                       
                            memset(vstd, 0, sizeof(vstd));
                            if(!pathy(y)) //如果没有增广路径. 
                                  printf(" %d", i-1); //那么该点就是最小点覆盖集中的点. 
                            else del[i] = 0;  
               }
    		   else
               {
                   x = my[i];
                   if(x==-1) continue;               
                   mx[x] = -1;
                   my[i] = -1;	
    			   if(del[x]) continue;
                   del[i] = 1;  
                   memset(vstd, 0, sizeof(vstd));
                   if(!pathx(x))
                           printf(" %d", i-1);
                   else del[i] = 0;
               }
         }
         printf("\n");
    }
    int main()
    {
        int cas, i, s, t;
        scanf("%d", &cas);
        while(cas--)
        {
                    scanf("%d %d", &nv, &ne);                
                    memset(grp, 0, sizeof(grp));
                    memset(wet, 0, sizeof(wet));              
                    for(i = 1; i <= nv; i++)
                          scanf("%d", &grp[i]);                
                    for(i = 1; i <= ne; i++)
                    {
                          scanf("%d %d", &s, &t);
                          s++;t++;
                          if(grp[s]==0 && grp[t]==1) wet[s][t] = 1;
                          if(grp[s]==1 && grp[t]==0) wet[t][s] = 1;
                    }               
                    MaxMatch();
        }
        return 0;
    }
    

  • 相关阅读:
    开博的第一天!
    使用EditText的addTextChangedListener(new TextWatcher())方法
    Activity的四种launchMode
    MySQL数据库
    BaseAdapter中重写getview的心得以及发现convertView回收的机制
    与数据库打交道的Adapter----SimpleCursorAdapter
    [原创] Fragment的添加、移除问题
    Datum Form Goole Android
    app包中的fragment和v4包中的fragment的使用的区别
    LayoutInflater类详解
  • 原文地址:https://www.cnblogs.com/nanke/p/2151456.html
Copyright © 2011-2022 走看看