zoukankan      html  css  js  c++  java
  • [2018湖南省队集训] 6.24 T1 marshland

    题面在这里!

        一开始感觉像一个类似二分图的最小割,于是成功跑偏2333333

        很容易发现一个关键性质,'L'的两个角落在的偶数格 的行(或者列)的奇偶性一定不同。。。。

        于是我们再把偶数格按照行(或者列)的奇偶性再细分成 两类,可以发现只有一个奇数格向旁边的两类偶数格都有空挡的话,才能放下一个L。

        所以我们把放L看成网络中的一条流量,要经过三种点,于是对于奇数格拆点限流然后四列点直接跑最大费用最大流就行了。。。。

       

        因为不用把m个L都放完,所以增广到 dis<0 的时候跳出就好啦。。。。

    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<cstring>
    #define ll long long
    using namespace std;
    #define pb push_back
    const int N=10005;
    
    vector<int> g[N];
    struct lines{
    	int from,to,flow,cap,cost;
    }l[N*73];
    int dx[4]={0,0,1,-1},dy[4]={1,-1,0,0},X,Y;
    int S,T,t=-1,d[N],p[N],a[N],n,m,ans;
    int val[55][55],id[55][55],cnt,k;
    bool iq[N],ban[55][55];
    
    inline void add(int from,int to,int cap,int cost){
    	l[++t]=(lines){from,to,0,cap,cost},g[from].pb(t);
    	l[++t]=(lines){to,from,0,0,-cost},g[to].pb(t);
    }
    
    inline bool SPFA(){
    	memset(d,-0x3f,sizeof(d)),d[S]=0,p[S]=0;
    	queue<int> q; q.push(S),a[S]=1<<30;
    	int x,pre; lines e;
    	
    	while(!q.empty()){
    		x=q.front(),q.pop();
    		
    		for(int i=g[x].size()-1;i>=0;i--){
    			e=l[g[x][i]];
    			if(e.flow<e.cap&&d[x]+e.cost>d[e.to]){
    				d[e.to]=d[x]+e.cost;
    				a[e.to]=min(a[x],e.cap-e.flow);
    				p[e.to]=g[x][i];
    				if(!iq[e.to]) iq[e.to]=1,q.push(e.to); 
    			}
    		}
    		
    		iq[x]=0;
    	}
    	
    	if(d[T]<0) return 0;
    	
    	if(a[T]>=m){ ans-=d[T]*m; return 0;}
    	
    	ans-=d[T]*a[T],m-=a[T];
    	
    	for(x=T;x!=S;x=l[pre].from){
    		pre=p[x],l[pre].flow+=a[T];
    		l[pre^1].flow-=a[T];
    	}
    	
    	return 1;
    } 
    
    inline void solve(){
        S=0,T=cnt+1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) if(!ban[i][j])
                if(i+j&1) add(id[i][j],id[i][j]+cnt,1,val[i][j]);
                else if(i&1){
                	add(S,id[i][j],1,0);
                	for(int u=0;u<4;u++){
                		X=i+dx[u],Y=j+dy[u];
                		if(id[X][Y]) add(id[i][j],id[X][Y],1,0);
    				}
    			}
    			else{
                	add(id[i][j],T,1,0);
                	for(int u=0;u<4;u++){
                		X=i+dx[u],Y=j+dy[u];
                		if(id[X][Y]) add(id[X][Y]+cnt,id[i][j],1,0);
    				}				
    			}
    	
    	while(SPFA());
    }
    
    int main(){
    //	freopen("marshland.in","r",stdin);
    //	freopen("marshland.out","w",stdout);
    	
    	scanf("%d%d%d",&n,&m,&k);
    
    	for(int i=1;i<=n;i++)
    	    for(int j=1;j<=n;j++){
    		    scanf("%d",&val[i][j]);
    			id[i][j]=++cnt,ans+=val[i][j];
            }
            
    	while(k--) scanf("%d%d",&X,&Y),ban[X][Y]=1;
    	
    	solve();
    	
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

  • 相关阅读:
    linux 学习笔记
    linux 子系统折腾记 (三)
    linux子系统折腾记 (二)
    windows linux 子系统折腾记
    会计学习笔记(非专业)
    linux 大冒险
    coreRT 和 Native 编译netcore AOT程序
    dotnet core如何编译exe
    win10的hyper-v共享文件夹
    packagereference 里面的资产是怎么回事?
  • 原文地址:https://www.cnblogs.com/JYYHH/p/9245543.html
Copyright © 2011-2022 走看看