srm 558 div1 1000 SurroundingGame(最小割构图题)

Problem Statement

 Surrounding Game is a single-player game played on a rectangular grid of cells. Cells are considered adjacent if they share a common side. (Hence, each cell has at most four adjacent cells. The cells on the sides and in the corners of the grid have fewer adjacent cells than the ones inside the grid.) 



The game is played by placing stones into some of the cells. Each cell may only contain at most one stone. A cell is called dominated if at least one of the following two conditions holds:
  • The cell contains a stone.
  • All cells adjacent to the cell contain stones.


Each cell of the grid contains two numbers, each from 0 to 61, inclusive: the cost of placing a stone into the cell, and the benefit from dominating the cell. At the end of the game, the overall score of the player is the sum of all benefits minus the sum of all costs. 



You are given the vector <string>s cost and benefit. The characters cost[i][j] and benefit[i][j] represent the two numbers written in the cell (i,j), using the following encoding:
  • Characters '0'-'9' represent numbers 0-9.
  • Characters 'a'-'z' represent numbers 10-35.
  • Characters 'A'-'Z' represent numbers 36-61.


For example, if character 7 of element 4 of cost is 'B', the cost of placing a stone into the cell (4,7) is 37. 



Calculate and return the maximal possible score for the given grid.

Definition

 
Class:SurroundingGame
Method:maxScore
Parameters:vector <string>, vector <string>
Returns:int
Method signature:int maxScore(vector <string> cost, vector <string> benefit)
(be sure your method is public)
 
 

Constraints

-cost will contain between 2 and 20 elements, inclusive.
-cost and benefit will contain the same number of elements.
-Each element of cost will contain between 2 and 20 characters, inclusive.
-Each element of cost will contain the same number of characters.
-Each element of benefit will contain the same number of characters as element 0 of cost.
-Each character in cost and benefit will be a character from '0'-'9','a'-'z', or 'A'-'Z'.

Examples

0) 
 
{"21","12"}
{"21","12"}
Returns: 4
The optimal solution is to put stones into (0,1) and (1,0). All the cells will be dominated and the overall score will be 6 - 2 = 4.
1) 
 
{"ZZ","ZZ"}
{"11","11"}
Returns: 0
The optimal solution is to put no stones. It is impossible to get a positive score.
2) 
 
{"XXX","XXX","XXX"}
{"aaa","aZa","aaa"}
Returns: 2
The optimal solution is to put a stone into (1,1).
3) 
 
{"asam","atik"}
{"123A","45BC"}
Returns: 71
 
4) 
 
{"IIIIIIII",
 "IIWWWWII",
 "IIWIIIII",
 "IIWIIIII",
 "IIWWWWII",
 "IIIIIWII",
 "IIIIIWII",
 "IIWWWWII",
 "IIIIIIII"}
{"IIIIIIII",
 "II0000II",
 "II0II0II",
 "II0II0II",
 "II0000II",
 "II0II0II",
 "II0II0II",
 "II0000II",
 "IIIIIIII"}
Returns: 606
题意:给你一个n*m的方阵,每个方阵可以放石头,每个格子放石头需要花费,对于一个格子,如果放了石头,或者它周围的格子都放了石头,则它将带来收益。。。问,怎样放石头,使得收益-花费的值最大


分析:类似这样的题做得挺多,看完不久,便想到可能是最小割的应用,然后就是长久的挣扎,下面就说说别人的构图吧,我自己还没完全明白= = 看了很多人的代码,就下面这个构图简单,而且明白一点点

首先将所有格子黑白涂色,将每个格子分成两个节点,然后虚拟源点S和汇点T,对于黑色格子i,建两条边,S到i,容量为花费,i到i'容量为收益,对于白色格子j,也是两条边,j到T,容量为花费,j'到j容量为收益,对于i与j相邻的,也建立两条边,i到j',和i'到j,容量都是无穷,这样做最大流,答案就是所有收益-最大流的值

仔细推敲了下,这个模型是假设取了所有格子的收益,然后怎样摆放石子,使得花费最小,也就是这个模型就是求最小花费的,中间两条容量为收益的边正好限制花费不超过收益,在这个前提下,使得总花费最小,这就是我大概的理解

希望有谁会这道题,指导我下

PS:由于比赛时做完一题就剩20分钟,弱菜无力。。。看完这题就剩6分钟了,立马贴了个模板,随便构图,最后样例都调不出来,本来后悔不应该中途放松的,比赛后才发现就算做了我也做不出来,这题不是简单题 T_T

冥思苦想了两天,还是没想出怎样构图,无奈看了别人的代码,还是懵懵懂懂,不过这回ID变黄了,贴下来当纪念吧,嘿嘿


代码:

// BEGIN CUT HERE

// END CUT HERE
#line 5 "SurroundingGame.cpp"
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<iostream>
#include<sstream>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<fstream>
#include<numeric>
#include<iomanip>
#include<bitset>
#include<list>
#include<stdexcept>
#include<functional>
#include<utility>
#include<ctime>
using namespace std;
#define PB push_back
#define MP make_pair
#define REP(i,n) for(i=0;i<(n);++i)
#define FOR(i,l,h) for(i=(l);i<=(h);++i)
#define FORD(i,h,l) for(i=(h);i>=(l);--i)
typedef vector<int> VI;
typedef vector<string> VS;
typedef vector<double> VD;
typedef long long LL;
typedef pair<int,int> PII;
const int mm=1000000;
const int mn=22222;
const int oo=1000000000;
int node,src,dest,edge;
int reach[mm],flow[mm],next[mm];
int head[mn],work[mn],dis[mn],q[mn];
inline int min(int a,int b)
{
    return a<b?a:b;
}
inline void prepare(int _node,int _src,int _dest)
{
    node=_node,src=_src,dest=_dest;
    for(int i=0;i<node;++i)head[i]=-1;
    edge=0;
}
inline void addedge(int u,int v,int c)
{
    reach[edge]=v,flow[edge]=c,next[edge]=head[u],head[u]=edge++;
    reach[edge]=u,flow[edge]=0,next[edge]=head[v],head[v]=edge++;
}
bool Dinic_bfs()
{
    int i,u,v,l,r=0;
    for(i=0;i<node;++i)dis[i]=-1;
    dis[q[r++]=src]=0;
    for(l=0;l<r;++l)
        for(i=head[u=q[l]];i>=0;i=next[i])
            if(flow[i]&&dis[v=reach[i]]<0)
            {
                dis[q[r++]=v]=dis[u]+1;
                if(v==dest)return 1;
            }
    return 0;
}
int Dinic_dfs(int u,int exp)
{
    if(u==dest)return exp;
    for(int &i=work[u],v,tmp;i>=0;i=next[i])
        if(flow[i]&&dis[v=reach[i]]==dis[u]+1&&(tmp=Dinic_dfs(v,min(exp,flow[i])))>0)
        {
            flow[i]-=tmp;
            flow[i^1]+=tmp;
            return tmp;
        }
    return 0;
}
int Dinic_flow()
{
    int i,ret=0,delta;
    while(Dinic_bfs())
    {
        for(i=0;i<node;++i)work[i]=head[i];
        while(delta=Dinic_dfs(src,oo))ret+=delta;
    }
    return ret;
}
int get(char a)
{
    if(a>='0'&&a<='9')return a-'0';
    if(a>='a'&&a<='z')return a-'a'+10;
    if(a>='A'&&a<='Z')return a-'A'+36;
    return 0;
}
int dx[]={0,0,-1,1};
int dy[]={-1,1,0,0};
class SurroundingGame
{
public:
    int maxScore(vector <string> cost, vector <string> benefit)
    {
        int i,j,k,x,y,n=cost.size(),m=cost[0].size(),sum=0;
        prepare(n*m*2+2,0,n*m*2+1);
        for(i=0;i<n;++i)
            for(j=0;j<m;++j)
            {
                sum+=get(benefit[i][j]);
                if((i+j)%2)
                {
                    addedge(src,i*m+j+1,get(cost[i][j]));
                    addedge(i*m+j+1,n*m+i*m+j+1,get(benefit[i][j]));
                }
                else
                {
                    addedge(n*m+i*m+j+1,i*m+j+1,get(benefit[i][j]));
                    addedge(i*m+j+1,dest,get(cost[i][j]));
                }
                for(k=0;k<4;++k)
                {
                    x=i+dx[k];
                    y=j+dy[k];
                    if(x<0||x>=n||y<0||y>=m)continue;
                    if((i+j)%2)addedge(n*m+i*m+j+1,x*m+y+1,oo);
                    else addedge(x*m+y+1,n*m+i*m+j+1,oo);
                }
            }
        sum-=Dinic_flow();
        return sum;
    }

// BEGIN CUT HERE
	public:
	void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); }
	private:
	template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
	void verify_case(int Case, const int &Expected, const int &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
	void test_case_0() { string Arr0[] = {"21","12"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"21","12"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 4; verify_case(0, Arg2, maxScore(Arg0, Arg1)); }
	void test_case_1() { string Arr0[] = {"ZZ","ZZ"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"11","11"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 0; verify_case(1, Arg2, maxScore(Arg0, Arg1)); }
	void test_case_2() { string Arr0[] = {"XXX","XXX","XXX"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"aaa","aZa","aaa"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 2; verify_case(2, Arg2, maxScore(Arg0, Arg1)); }
	void test_case_3() { string Arr0[] = {"asam","atik"}; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"123A","45BC"}; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 71; verify_case(3, Arg2, maxScore(Arg0, Arg1)); }
	void test_case_4() { string Arr0[] = {"IIIIIIII",
 "IIWWWWII",
 "IIWIIIII",
 "IIWIIIII",
 "IIWWWWII",
 "IIIIIWII",
 "IIIIIWII",
 "IIWWWWII",
 "IIIIIIII"}
; vector <string> Arg0(Arr0, Arr0 + (sizeof(Arr0) / sizeof(Arr0[0]))); string Arr1[] = {"IIIIIIII",
 "II0000II",
 "II0II0II",
 "II0II0II",
 "II0000II",
 "II0II0II",
 "II0II0II",
 "II0000II",
 "IIIIIIII"}
; vector <string> Arg1(Arr1, Arr1 + (sizeof(Arr1) / sizeof(Arr1[0]))); int Arg2 = 606; verify_case(4, Arg2, maxScore(Arg0, Arg1)); }

// END CUT HERE

};
// BEGIN CUT HERE
int main()
{
    SurroundingGame ___test;
    ___test.run_test(-1);
    return 0;
}
// END CUT HERE


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值