列表

详情


NC200010. 雷顿女士与多米诺骨牌

描述

卡特莉发现了一个关于多米诺骨牌的谜题。

现在她的面前有一个n行m列的棋盘,棋盘上的每个格子有各自的权值,特别有趣的是,这些权值有正有负。

现在卡特莉要把若干个1×2或2×1的多米诺骨牌摆放在棋盘上,然后她就可以取得被骨牌覆盖的格子的权值。请注意骨牌之间不能有重叠部分,也不能摆放伸出棋盘外的骨牌。

正如你猜的那样,卡特莉想要尽可能多地得到权值,请你求出她可以得到的最大权值和。

出于对解密的热爱,卡特莉对棋盘上的格子可能会特殊的偏好。一些格子必定会被她摆放的骨牌覆盖。相反地,还有一些格子必定不会被她摆放的格子覆盖。

输入描述

第一行输入一个T(1<=T<=1000)表示数据组数。

接下来T组数据。

对于每组数据,第一行输入一个n,m(1<=n,m<=50),分别表示行列数。

保证对于超过的数据,max(n,m)<=10,保证这部分数据是随机生成的。

每个格子的权值绝对值小于等于1000。

接下来输入n行m列的字符。

对于每个位置的字符:

表示可以任意选择覆盖或者不覆盖。

表示该位置不能被覆盖。

表示该位置必须被覆盖。

接下来再输入n行m列个数字。

每个位置的数字表示这个位置格子的权值。

输出描述

对于每组数据,请你输出卡特莉可以得到的最大权值。
如果不存在任何一组满足题目要求的方案,则输出"no solution"。(不包含引号)

示例1

输入:

3
3 3
...
.*.
...
1 1 1
1 0 1
1 1 1
3 3
###
###
###
1 2 3
4 5 6
7 8 9
3 3
...
..#
...
10 8 6
12 1 -10
1 3 5

输出:

8
no solution
35

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++ 解法, 执行用时: 286ms, 内存消耗: 1908K, 提交时间: 2021-06-28 19:04:22

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define int long long
int n,m,s,t,cnt,flowans,costans,pt;
int to[26005], nxt[26005], head[26005], cur[26005], d[26005], val[26005],A[55][55],B[55][55];
int dis[25000],vis[25000],inc[25000],pre[25000],a[55][55];
bool Vis[25005];
const int INF=0x3f3f3f3f,INF1=0x3f3f3f3f3f3f3f3fLL;
void add(int u, int v, int w,int anow) {
//	cout<<u<<" "<<v<<" "<<w<<" "<<anow<<endl;
    to[++cnt] = v;
    val[cnt] = w;
    d[cnt] = anow;
    nxt[cnt] = head[u];
    head[u] = cnt;
    to[++cnt]=u;
    val[cnt]=0;
    d[cnt]=-anow;
    nxt[cnt]=head[v];
    head[v]=cnt;
}
bool SPFA(){
	queue<int>Q;
	fill(dis,dis+pt+1,INF1);
	memset(vis,0,sizeof vis);
	memset(Vis,0,sizeof Vis);
	Q.push(s);
	inc[s]=INF1;
	dis[s]=0,vis[s]=1; 
	Vis[s]=1;
	while(!Q.empty()){
		int u=Q.front();
		Q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=nxt[i]){
			if(!val[i])continue;
			int v=to[i];
			Vis[v]=1;
			if(dis[v]>dis[u]+d[i]){
				dis[v]=dis[u]+d[i];
				pre[v]=i; 
				inc[v]=min(inc[u],val[i]);
				if(!vis[v])vis[v]=1,Q.push(v);
			} 
		}
	}
	if(!Vis[t]||dis[t]>=0)return 0;
	return 1;
}
void max_flow_min_cost(){
	while(SPFA()){
		flowans+=inc[t];
		costans+=dis[t]*inc[t];
		int x=t,i;
		while(x!=s){
			i=pre[x];
			val[i]-=inc[t];
			val[i^1]+=inc[t];
			x=to[i^1];
		}
	}
}
char S[55][55];
int dx[5]={-1,1,0,0},dy[5]={0,0,-1,1};
signed main(){
	int T;
	cin>>T;
    int xd=0;
	while(T--){
		memset(cur,0,sizeof cur);
		memset(A,0,sizeof A);
		memset(B,0,sizeof B);
		memset(head,0,sizeof head);
		memset(d,0,sizeof d);
		memset(nxt,0,sizeof nxt);
		flowans=costans=0;
		cin>>n>>m;
		for(int i=1;i<=n;i++)scanf("%s",S[i]+1);
		cnt=1;pt=0;
		s=pt++,t=pt++;
		for(int i=1;i<=n;i++)
			for(int j=1;j<=m;j++){
				cin>>a[i][j];
				A[i][j]=pt++;
				B[i][j]=pt++;
			}
		int mu=0;
		for(int i=1;i<=n;i++){
			for(int j=1;j<=m;j++){
				if(S[i][j]=='#'){
					mu++;
					add(A[i][j],B[i][j],1,-a[i][j]-INF);
				}
				if(S[i][j]=='.'){
					add(A[i][j],B[i][j],1,-a[i][j]);
				}
				if((i+j)&1){
					add(s,A[i][j],1,0);
					for(int k=0;k<=3;k++){
						int x=i+dx[k],y=j+dy[k];
						if(x>=1&&x<=n&&y>=1&&y<=m){
							add(B[i][j],A[x][y],1,0);
						}
					}	
				}else{
					add(B[i][j],t,1,0);
				}
			}
		}
		max_flow_min_cost();
		costans+=1ll*mu*INF;
		if(abs(costans)>=1ll*n*m*1000){
			cout<<"no solution"<<endl;
		}else cout<<-costans<<endl;
	}
	return 0;
} 
/*
1
3 3
...
..#
...
1000 1000 1000
-144 -999 152
442 71 -666 
3
3 3
...
.*.
...
1 1 1
1 0 1
1 1 1
3 3
###
###
###
1 2 3
4 5 6
7 8 9
3 3
...
..#
...
10 8 6
12 1 -10
1 3 5
*/

上一题