1. 程式人生 > >[2018湖南省隊集訓] 6.24 T1 marshland

[2018湖南省隊集訓] 6.24 T1 marshland

online 不用 clas pre esp val ron www. mar

題面在這裏!

一開始感覺像一個類似二分圖的最小割,於是成功跑偏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\n",ans);
	return 0;
}

  

[2018湖南省隊集訓] 6.24 T1 marshland