zoukankan      html  css  js  c++  java
  • P6931 [ICPC2017 WF]Mission Improbable

    P6931 [ICPC2017 WF]Mission Improbable

    给定一个 r imes cr×c 的平面,在上面摆有一些箱子。我们可以得到他的三视图(如下图,左边矩阵上的值为平面上每一位摆放的箱子个数,右边三个视图为正视图,俯视图,左视图):

    你可以拿走一些箱子,和重新排列这些箱子的位置,你想知道,最多能拿走多少个箱子,使得这些箱子重新排列后正视图,俯视图,左视图不变?

    比如上面这个例子,下面这种拿走 99 个箱子后的重新排列方式也是可以的:

    1 le r,c le 1001≤r,c≤100,平面上每一个位置的箱子个数在 [0,10^9][0,10
    9
    ] 内。


    エラー発生:边数应该是(maxn * maxn) 的。。 开小了查到半夜 哇巨蠢


    Solution

    贪心加二分图匹配

    首先我们满足俯视图要求, 在有格子的地方全放上1先
    贪心, 每一行/每一列, 我们只需要堆一次最高的箱子就行了
    进一步贪心, 我们想让某一竖的箱子, 即对长的最大值产生贡献, 又对宽的最大值产生贡献。
    那么跑一次二分图匹配, 看一下哪行哪列的箱子可以对应一下, 并且交点处满足俯视图可以放箱子, 连边跑匈牙利就行

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    #define REP(i, x, y) for(LL i = (x);i <= (y);i++)
    using namespace std;
    LL RD(){
        LL out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const LL maxn = 110;
    LL head[maxn * 2],nume = 1;
    struct Node{
        LL v,dis,nxt;
        }E[maxn * maxn];
    void add(LL u,LL v,LL dis){
        E[++nume].nxt = head[u];
        E[nume].v = v;
        E[nume].dis = dis;
        head[u] = nume;
        }
    	
    LL x, y;
    LL map[maxn][maxn];
    LL x_max[maxn], y_max[maxn];
    LL used[maxn * 2], mat[maxn * 2];
    bool match(LL u){//二分图匹配
    	for(LL i = head[u];i;i = E[i].nxt){
    		LL v = E[i].v;
    		if(!used[v]){
    			used[v] = 1;
    			if(!mat[v] || match(mat[v])){
    				mat[v] = u;
    				mat[u] = v;
    				return 1;
    				}
    			}
    		}
    	return 0;
    	}
    void Hungary(){
    	REP(i, 1, x){
    		if(!mat[i]){
    			memset(used, 0, sizeof(used));
    			match(i);
    			}
    		}
    	}
    LL ans;
    void init(){
    	x = RD(), y = RD();
    	REP(i, 1, x)REP(j, 1, y){
    		map[i][j] = RD();
    		if(map[i][j] != 0)ans += map[i][j] - 1;//满足俯视图,贪心全拿走
    		}
    	REP(i, 1, x)REP(j, 1, y)x_max[i] = max(x_max[i], map[i][j]);
    	REP(i, 1, y)REP(j, 1, x)y_max[i] = max(y_max[i], map[j][i]);
    		
    	REP(i, 1, x){
    		REP(j, 1, y){
    			if(x_max[i] == y_max[j] && map[i][j] != 0 && x_max[i] != 0)
    				add(i, maxn + j + 1, 1);
    			}
    		}
    	}
    void work(){
    	Hungary();
    	
    	REP(i, 1, y)
    		if(y_max[i])//保证下加的1
    			ans -= y_max[i] - 1;//先把竖着的放上去
    			
    
    	REP(i, 1, x){
    		if(!mat[i] && x_max[i])
    			ans -= x_max[i] - 1;
    		}
    	cout<<ans<<endl;
    	}
    int main(){
    	init();
    	work();
    	return 0;
    	}
    
  • 相关阅读:
    合并n个链表
    合并2个链表
    删除链表中的倒数第n个元素
    判断字符串是否回文字符串
    回文链表
    反转链表
    反转链表2
    冒泡排序法
    编译datax(3.x版本)踩的坑,记录修改记录
    Python基本知识(6)——集合
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/14408060.html
Copyright © 2011-2022 走看看