[BZOJ 3753]Wall

来源:互联网 发布:邮箱大师mac下载 编辑:程序博客网 时间:2024/05/14 17:36

一类维护连通性的DP

要将图进行转化。


3.1 题目描述
众所周知,GFW 的出现促进了社会的和谐。Wayne 于是想研究一下GFW。
Wayne 喜欢网格,所以他把一些网站排成了N M 的网格,每个格子代表一个网站。每个网
站有一个评分,当然评分可正可负。现在Wayne 想用一堵“墙”围住一些网站,使得评分和最大。
所谓“墙”,就是一个由网格的边组成的简单多边形,不能自交,也不能有空洞。
过了一会儿Wayne 发现这个模型太一般了。出于一些原因,有些网站必须在“墙”外,我们称之
为“坏网站”;而有些网站必须在“墙”内,我们称之为“好网站”。当然了,“坏网站”的评分不一定
低,“好网站”的评分不一定高。Wayne 又想知道,这种情况下,能够得到的最大评分和。注意,并
不总是存在合法的方案,所以当无法实现时,输出“Can not establish GFW.”。
3.2 输入格式
第一行两个正整数N 和M。
接下来N 行,每行M 个用空格隔开的整数,表示网站的权值。
最后N 行,每行M 个用空格隔开的整数,1 表示坏网站,2 表示好网站,0 表示其他网站。
3.3 输出格式
输出两行,第一行一个整数表示一堵“墙”能围住的最大评分和,第二行表示有限制时的答案。
3.4 样例输入
3 3
2 -1 2
-3 100 -3
-3 20 -3
2 0 2
0 1 0
0 0 0
3.5 样例输出
123
17
3.6 数据规模
对于20% 的数据,N = 1 或M = 1。
对于另外30% 的数据,N <= 3,M  <= 3。
对于100% 的数据,N <= 10,M  <= 10,权值的绝对值不超过106,且至少一个权值非负,至少一
个好网站。



#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <queue>#define maxn 20using namespace std;const int inf = 0x7fffffff;int ans;typedef long long ll;int n, m;int a[maxn][maxn], need[maxn][maxn];int QAQ, qaq;struct HashMap{#define N 2000010#define mod 997int f[N], h[mod + 10], nxt[N], size;ll st[N];void init(){memset(h, 0, sizeof h);size = 0;}void push(ll val, int ans){int tmp = val % mod;for(int i = h[tmp]; i; i = nxt[i]){if(st[i] == val){f[i] = max(f[i], ans);return;}}++ size;f[size] = ans;st[size] = val;nxt[size] = h[tmp];h[tmp] = size;}}dp[2];int code[maxn], ch[maxn];void Decode(ll st){for(int i = m; i >= 0; i --){code[i] = st & 7;st >>= 3;}}ll Encode(){ll st = 0;int cnt = 0;memset(ch, -1, sizeof ch);ch[0] = 0;for(int i = 0; i <= m; i ++){if(ch[code[i]] == -1)    ch[code[i]] = ++ cnt;code[i] = ch[code[i]];st <<= 3;st |= code[i];}return st;}void Shift(){for(int i = m; i >= 1; i --)    code[i] = code[i - 1];code[0] = 0;}bool Judge(int cnt, int i, int j){if(cnt && need[i][j] == 1)return false;if(!cnt && need[i][j] == 2)return false;return true;}void DP(int cur, int i, int j){dp[cur ^ 1].init();for(int k = 1; k <= dp[cur].size; k ++){Decode(dp[cur].st[k]);if(j == 1){if(code[m])continue;Shift();}int left = code[j - 1], up = code[j];bool cnt = 0;for(int p = 0; p < j - 1; p ++)    cnt ^= code[p] != 0;if(left && up){if(left == up){code[j] = code[j - 1] = 0;ll tmp = Encode();if(tmp == 0 && QAQ == qaq)ans = max(ans, dp[cur].f[k]);}else{if(Judge(cnt, i, j)){code[j] = code[j - 1] = 0;for(int p = 0; p <= m; p ++)    if(code[p] == up)        code[p] = left;dp[cur ^ 1].push(Encode(), dp[cur].f[k] + cnt * a[i][j]);}}}else if(left || up){int tmp = max(left, up);if(Judge(cnt, i, j)){code[j - 1] = 0;code[j] = tmp;dp[cur ^ 1].push(Encode(), dp[cur].f[k] + cnt * a[i][j]);}cnt ^= 1;if(Judge(cnt, i, j)){code[j - 1] = tmp;code[j] = 0;dp[cur ^ 1].push(Encode(), dp[cur].f[k] + cnt * a[i][j]);}}else{if(Judge(cnt, i, j)){code[j - 1] = code[j] = 0;dp[cur ^ 1].push(Encode(), dp[cur].f[k] + cnt * a[i][j]);}cnt ^= 1;if(Judge(cnt, i, j)){code[j - 1] = code[j] = 15;dp[cur ^ 1].push(Encode(), dp[cur].f[k] + cnt * a[i][j]);}}}}void Solve(){int cur = 0;dp[cur].init();dp[cur].push(0, 0);ans = -inf;for(int i = 1; i <= n; i ++){for(int j = 1; j <= m; j ++){DP(cur, i, j);cur ^= 1;if(need[i][j] == 2)    qaq ++;}}if(ans == -inf)printf("Can not establish GFW.\n");    else printf("%d\n",ans);}int main(){scanf("%d%d", &n, &m);n ++, m ++;for(int i = 1; i < n; i ++)for(int j = 1; j < m; j ++)scanf("%d", &a[i][j]);Solve();for(int i = 1; i < n; i ++)for(int j = 1; j < m; j ++){            scanf("%d", &need[i][j]);            if(need[i][j] == 2)                QAQ ++;}Solve();return 0;}



0 0
原创粉丝点击