uva 11419最小点覆盖和…

来源:互联网 发布:淘宝运送方式怎么设置 编辑:程序博客网 时间:2024/06/06 20:34
大概题意:在一个R*C大小的网格中,网格上面放着一些目标,可以在网格外面发射子弹,子弹可以沿着垂直或则水平的方向射出,并打掉该路径上的所有目标,问最少需要多少子弹,并把这些子弹的位置输出。

解法:每发射一个子弹,我们就能把某一行或者某一列的目标都清楚掉,因此我们每一行、每一列看成一个目标,并把这一行、列中的目标都标同一个号,那么我们就能通过同一个位置的目标来得到这个位置所在行、列的关系(在它们之间连一条边),我们要求的就转化为,用最少的点去覆盖所有的边,也就是最小点覆盖 , 也就是这个二分图的最大匹配。

子弹的位置:首先我们要知道 , 对于二分匹配算法 , 一定会遍历所有边 , 也就是说所有边都会属于一个或多个匈牙利树 。我们先把这些边分为匹配边和非匹配边 。 
   我们先来确定非匹配边的情况,对于一条非匹配边,我们可以确定这条边肯定有一个点或两个点都属于匹配点 , 对于只有一个点属于匹配点 ,那么我们肯定要选这个匹配点 , 因此 , 我们只需要在求出最大匹配之后 , 再用X集合中的非匹配点去发展匈牙利树 ,然后我们标记X集合和Y集合中已经走过的点 , 最后 X 中没有标记的点和 Y 中已经标记的点 , 就是子弹的位置 。由于我们是用非匹配点去发展匈牙利树 , 因此如果存在边 , 那么我们就一定要选这条边的另外一个点 , 并且这个点一定是匹配点 ,那么和这个点相连的所有边就已经都覆盖了 , 再往后面的匈牙利树 , 我们就能很容易得出了。
    对于匹配边 , 在我们后面已经得到的匈牙利树中 ,如果匹配边已经在这个树种 , 那么我们可以确定这条边肯定已经被覆盖 , 对于不在匈牙利树中的匹配边 ,我们可以确定这条匹配边上的X集合中的点 , 肯定没有被标记 , 那么根据上面的输出规则 , 我们可以确定用这中方法得到的点 ,肯定已经覆盖了所有边。


代码:


#define MAXN 1010#define INF 1000000#define max(x , y) (x)>(y)?(x):(y)#define min(x , y) (x)<(y)?(x):(y)int n , m , k; //  记录每条边的权值int pre[MAXN] ;  // 记录和y中点匹配的点是哪个点vectorgrap[MAXN];int wr[MAXN] , wc[MAXN];int cx[MAXN] , cy[MAXN];int bzx[MAXN] , bzy[MAXN];void init(){memset(wr , 0 , sizeof(wr));memset(wc , 0 , sizeof(wc));    for(int i = 1; i<= n; i++)    {       grap[i].clear();    }    memset(cx , -1 ,sizeof(cx));    memset(cy , -1 ,sizeof(cy));}bool match(int i)  // 寻找增广路{    bzx[i] = 1;    for(int j = 0; j< grap[i].size(); j++)    {       int v = grap[i][j];       if(!pre[v])       {           pre[v] =1;bzy[v] = 1;           if(cy[v]== -1 || match(cy[v]))           {              cx[i] = v;              cy[v] = i;              return true;           }       }       }    return false;}int km(){    int i ;    memset(bzx , 0 ,sizeof(bzx));memset(bzy , 0 , sizeof(bzy));    int res = 0;    for(i = 1; i<= n; i++)    {       if(cx[i] == -1&& wr[i])       {           memset(pre, 0 , sizeof(pre));          if(match(i))  res += 1;       }    }    return res;}int main(){    while(scanf("%d %d %d" ,&n , &m , &k) !=EOF)    {       if(n+m+k == 0)  break;       init();       int i , x , y ;       for(i = 1; i <= k; i++){scanf("%d %d" , &x ,&y);grap[x].push_back(y);wr[x] = wc[y] = 1;}       x = km();km();             printf("%d" , x);for(i = 1; i <= n; i++)if(!bzx[i] && wr[i]) printf(" r%d" , i);for(i = 1; i <= m; i++)if(bzy[i] && wc[i]) printf(" c%d" , i);cout<<endl;    }    return 0;}



0 0
原创粉丝点击