• codechef BIBOARD


    一个和标算不同的方法。
    考虑二元关系网络流(最小割)。
    根据sdoi墙上的句子的经验,把每个网格上的点拆成两个,代表黑/白点。
    给当前位置((x,y))新建两个点(a,b)
    a归到s->((x,y))选白色
    a归到t->((x,y))选黑色
    b归到s->((x,y))选黑色
    b归到t->((x,y))选白色
    考虑a->b连inf,这样子可以保证a,b不能同时选。
    s->a连接流量为(a)格子的代价,b->t连接流量为(b)格子代价
    如果限制格子((x,y))为黑色,则(s o a)不连边。
    如果限制格子((x,y))为白色,则(b o t)不连边。
    考虑矩形的限制。
    把每个矩形新建两个点(c,d)
    如果我们为一个格子((x,y))赋值。
    假设当前格子是白色,则包含它的黑矩形都不能选。
    假设当前格子是黑色,则包含它的白矩形都不能选。
    s->c,d->t连代价的边(如果当前矩形包含不是它颜色的点,则不连)。
    根据前面的经验,((x,y))对应的点(a,b),d->b连inf,a->c连inf。
    c->d连inf,表示c和d不能同时选
    发现这样子跑出来的是“最小要减少的代价”
    设变量(ans),初始为(0)
    考虑每个格子,如果它必须是黑色,则ans+=它为黑色时的代价。
    如果它必须是白色,则ans+=它为白色时的代价。
    否则ans+=它为白色时的代价+它为黑色时的代价
    对于每个矩形,如果这个矩形和t/s有边,则ans+=这个矩形的代价
    ans-最小割就是答案。
    (上面的做法错了)
    还是考虑最小割。
    对于每个格子建立一个点,如果这个点被归到s集合就是白色,否则是黑色。
    考虑对于每个正方形拆成2个点((a,b)),表示这个矩形为黑/白。
    a归到s->正方形选白色
    a归到t->正方形选黑色
    b归到s->正方形选黑色
    b归到t->正方形选白色
    把a对格子对应的点连接inf,格子对应的点和b连inf。
    如果正方形能够选白色,则s->a连接权值为代价的边,ans+=代价。
    如果正方形能够选黑色,则b->t连接权值为代价的边,ans+=代价。
    ans-最小割就是答案。

    #include<bits/stdc++.h>
    using namespace std;
    #define N 1000010
    #define int long long
    int T;
    int h[N],nxt[N],v[N],w[N],s,t,dep[N],ec,ans,v1[N],v2[N],inf=1e10,n,m,id[510][510],st[N],tp;
    char c[1000][1000];
    void add(int x,int y,int z){
    	v[++ec]=y;
    	w[ec]=z;
    	nxt[ec]=h[x];
    	h[x]=ec;
    }
    void adj(int x,int y,int z){
    	add(x,y,z);
    	add(y,x,0);
    }
    bool bfs(){
        queue<int>q;
    	q.push(s);
        for(int i=1;i<=ec;i++)
        	dep[i]=0;
    	dep[s]=1;
        while(!q.empty()){
            int x=q.front();q.pop();
            for(int i=h[x];i;i=nxt[i])
                if(w[i]&&!dep[v[i]]){
                	dep[v[i]]=dep[x]+1;
    				q.push(v[i]);
                	if(v[i]==t)
    					return 1;
    			}
        }
    	return 0;
    }
    int dfs(int x,int dis){
        if(x==t)return dis;
    	int tp=dis;
        for(int i=h[x];i;i=nxt[i])
            if(dep[v[i]]==dep[x]+1&&w[i]){
                int f=dfs(v[i],min(tp,w[i]));
                if(!f)
    				dep[v[i]]=0;
                tp-=f;
                w[i]-=f;
    			w[i^1]+=f;
                if(!tp)
    				break;
            }
        return dis-tp;
    }
    int din(){
        int aans=0;
        while(bfs()){
        	int v;
        	while(v=dfs(s,inf))
    			aans+=v;
    	}
        return aans;
    }
    signed main(){
    	scanf("%lld",&T);
    	while(T--){
    		scanf("%lld%lld",&n,&m);
    		ec=1;
    		ans=0;
    		memset(h,0,sizeof(h));
    		for(int i=1;i<=n;i++)
    			scanf("%s",c[i]+1);
    		for(int i=1;i<=min(n,m);i++)
    			scanf("%lld",&v1[i]);
    		for(int i=1;i<=min(n,m);i++)
    			scanf("%lld",&v2[i]);
    		s=1;
    		t=2;
    		int cc=2;
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++)
    				if(c[i][j]=='?')
    					id[i][j]=++cc;
    		for(int i=1;i<=n;i++)
    			for(int j=1;j<=m;j++)
    				for(int k=1;k<=min(i,j);k++){
    					int d[3]={0,0,0};
    					tp=0;
    					for(int a=i-k+1;a<=i;a++)
    						for(int b=j-k+1;b<=j;b++){
    							if(c[a][b]=='?'){
    								d[2]++;
    								st[++tp]=id[a][b];
    							}
    							if(c[a][b]=='0')
    								d[0]++;
    							if(c[a][b]=='1')
    								d[1]++;
    						}
    					if(!tp){
    						if(d[0]==k*k)
    							ans+=v1[k];
    						if(d[1]==k*k)
    							ans+=v2[k];
    					}
    					else{
    						if(d[0]+d[2]==k*k){
    							cc++;
    							ans+=v1[k];
    							for(int l=1;l<=tp;l++)
    								adj(cc,st[l],inf);
    							adj(s,cc,v1[k]);
    						}
    						if(d[1]+d[2]==k*k){
    							cc++;
    							ans+=v2[k];
    							for(int l=1;l<=tp;l++)
    								adj(st[l],cc,inf);
    							adj(cc,t,v2[k]);
    						}
    					}
    				}
    		printf("%lld
    ",ans-din());
    	}
    }
    
  • 相关阅读:
    Nginx之keepalived高可用工具
    Linux安装Nginx
    Nginx解决服务器宕机问题
    前端知识小札
    SQL入门(3):定义约束/断言assertion/触发器trigger
    SQL入门(2): Oracle内置函数-字符/数值/日期/转换/NVL/分析函数与窗口函数/case_decode
    Excel VBA入门(8): 快捷键/内置常量/代码调试/错误处理/代码优化
    小学生都看得懂的C语言入门(6): 字符串
    小学生都看得懂的C语言入门(5): 指针
    小学生都看得懂的C语言入门(4): 数组与函数
  • 原文地址:https://www.cnblogs.com/ctmlpfs/p/14390907.html
Copyright © 2020-2023  润新知