NOIP200003方格取数
难度级别: D; 编程语言:不限;运行时间限制:1000ms; 运行空间限制:51200KB; 代码长度限制:2000000B
试题描述

XYZ 是首师大附中信息技术团编程大神之一,尤其近两个月水平提升迅猛,一发不可收拾。老师说他前途不可估量,于是他有一点小骄傲,好像没有什么题能难住他。这让另一位编程高手 WJH 看不下去了,于是要求出一道题考考他,如果 10 分钟内做不出来,以后不许再这么“嚣张”,XYZ 欣然同意。WJH 要求 XYZ 帮助 ZYT 解决一个问题:
    现有 N*N 的方格图( N<=10,将其中的某些方格中填入正整数,而其它的方格中放入数字 0。如下图所示(见样例): 
               
    ZYT 从图的左上角的 A 点出发,可以向下行走,也可以向右走,直到到达右下角的 B 点。在走过的路上,ZYT 可以取走方格中的数(取走后的方格中将变为数字 0 )。从 A 点到 B 点共走两次,你必须指导ZYT所取数之和最大。如果得到正确的最大值他可以找杨老师获得该最大数的 10 倍积分,如果最大值错误,要跑步的( ZYT 最怕这个,你知道的)。

输入
第一行为一个整数 N(表示N*N的方格图),接下来的每行有三个整数,前两个表示位置,第三个数为该位置上所放的数。一行单独的0表示输入结束。
输出
只需输出一个整数,表示2条路径上取得的最大的和。
输入示例
8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0
输出示例
67
其他说明
数据范围:所有正整数都不会超过1000,太大了杨老师没那么多积分给的!

第一种方法是,我们可以使用费用流,对于每个点我们拆成两个点i,i`,并从i向i`连两条弧,容量均为1,一条费用为0,一条费用为-wi.

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
const int maxm=;
const int INF=;
struct ZKW {
int n,m,s,t,first[maxn],next[maxm];
int ans,cost;
int vis[maxn],inq[maxn],d[maxn];
struct Edge {int from,to,flow,cost;}edges[maxm];
void init(int n) {
this->n=n;m=;
memset(first,-,sizeof(first));
}
void AddEdge(int from,int to,int cap,int cost) {
edges[m]=(Edge){from,to,cap,cost};next[m]=first[from];first[from]=m++;
edges[m]=(Edge){to,from,,-cost};next[m]=first[to];first[to]=m++;
}
int BFS() {
queue<int> Q;
rep(i,,n) d[i]=INF;
d[t]=;inq[t]=;Q.push(t);
while(!Q.empty()) {
int x=Q.front();Q.pop();inq[x]=;
ren {
Edge& e=edges[i^];
if(e.flow&&d[e.from]>d[x]+e.cost) {
d[e.from]=d[x]+e.cost;
if(!inq[e.from]) inq[e.from]=,Q.push(e.from);
}
}
}
rep(i,,m-) edges[i].cost+=d[edges[i].to]-d[edges[i].from];
cost+=d[s];return d[s]!=INF;
}
int DFS(int x,int a) {
if(x==t||!a) {ans+=cost*a;return a;}
int flow=,f;vis[x]=;
ren {
Edge& e=edges[i];
if(e.flow&&!e.cost&&!vis[e.to]&&(f=DFS(e.to,min(a,e.flow)))) {
flow+=f;a-=f;
e.flow-=f;edges[i^].flow+=f;
if(!a) break;
}
}
return flow;
}
int solve(int s,int t) {
ans=cost=;this->s=s;this->t=t;
while(BFS()) do memset(vis,,sizeof(vis));while(DFS(s,INF));
return ans;
}
}sol;
int n,w[][];
int id(int x,int y,int t) {return t*n*n+(x-)*n+y;}
int main() {
n=read();sol.init(n*n*);
while() {
int x=read(),y=read(),v=read();
if(!x) break;
w[x][y]=v;
}
rep(i,,n) rep(j,,n) {
sol.AddEdge(id(i,j,),id(i,j,),,-w[i][j]);
sol.AddEdge(id(i,j,),id(i,j,),,);
if(i+<=n) sol.AddEdge(id(i,j,),id(i+,j,),,);
if(j+<=n) sol.AddEdge(id(i,j,),id(i,j+,),,);
}
printf("%d\n",-sol.solve(id(,,),id(n,n,)));
return ;
}

第二种方法是,我们使用DP。考虑一个人走两遍相当于两个人同时走,设f[x1][y1][x2][y2]表示第一个人走到了(x1,y1),第二个人走到了(x2,y2)最大收益。

转移时枚举上一次两个人在哪里,并加上这一步造成的收益:f[x1][y1][x2][y2]=Max(f[x1-1][y1][x2-1][y2],f[x1][y1-1][x2][y2-1],f[x1-1][y1][x2][y2-1],f[x1][y1-1][x2-1][y2])+w[x1][y1]+(x1!=x2||y1!=y2)*w[x2][y2].时间复杂度为O(N^4)

注意因为同时走,x1+y1恒等于x2+y2,可以将时间复杂度优化为O(N^3).

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i!=-1;i=next[i])
using namespace std;
inline int read() {
int x=,f=;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
}
const int maxn=;
int n,w[maxn][maxn],f[maxn][maxn][maxn];
int max(int a,int b,int c,int d) {
return max(max(a,b),max(c,d));
}
int dp(int x1,int y1,int x2) {
if(x1==&&y1==) return w[][];
int y2=x1+y1-x2;
if(x1<||x2<||x1>n||x2>n||y1<||y2<||y1>n||y2>n) return -<<;
int& ans=f[x1][y1][x2];
if(ans>=) return ans;
int tmp=max(dp(x1-,y1,x2-),dp(x1,y1-,x2-),dp(x1,y1-,x2),dp(x1-,y1,x2));
return ans=tmp+w[x1][y1]+(x1==x2?:)*w[x2][y2];
}
int main() {
memset(f,-,sizeof(f));
n=read();
while() {
int x=read(),y=read(),v=read();
if(!x) break;
w[x][y]=v;
}
printf("%d\n",dp(n,n,n));
return ;
}

NOIP200003方格取数的更多相关文章

  1. HDU 1565&1569 方格取数系列(状压DP或者最大流)

    方格取数(2) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  2. vijos 1563 疯狂的方格取数

    P1653疯狂的方格取数 Accepted 标签:天才的talent[显示标签]   背景 Due to the talent of talent123,当talent123做完NOIP考了两次的二取 ...

  3. [HDU 1565+1569] 方格取数

    HDU 1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  4. 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)

      HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...

  5. HDU-1565 方格取数(1)

    http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others)    Me ...

  6. BZOJ 1475: 方格取数( 网络流 )

    本来想写道水题....结果调了这么久!就是一个 define 里面少加了个括号 ! 二分图最大点权独立集...黑白染色一下 , 然后建图 : S -> black_node , white_no ...

  7. [动态规划]P1004 方格取数

    ---恢复内容开始--- 题目描述 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放 人数字0.如下图所示(见样例): A 0 0 0 0 0 0 0 0 0 ...

  8. P2045 方格取数加强版

    P2045 方格取数加强版 题目描述 给出一个n*n的矩阵,每一格有一个非负整数Aij,(Aij <= 1000)现在从(1,1)出发,可以往右或者往下走,最后到达(n,n),每达到一格,把该格 ...

  9. 线性规划与网络流24题●09方格取数问题&13星际转移问题

    ●(做codevs1908时,发现测试数据也涵盖了1907,想要一并做了,但因为“技术”不佳,搞了一上午) ●09方格取数问题(codevs1907  方格取数3) 想了半天,也没成功建好图: 无奈下 ...

随机推荐

  1. ubuntu14.04安装chrome

    到https://www.google.com/chrome/browser/desktop/index.html可下载指定版本的deb文件. 32bit: wget https://dl.googl ...

  2. 对Excel文件的操作

    ①.将文件设为“嵌入的资源”,Template修改不灵活:Stream stream=this.GetType().Assembly.GetManifestResourceStream(Templat ...

  3. Android 相机对焦模式

    Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE  Camer ...

  4. Android 中的openurl

    在iOS中这么叫,在android中不知道是不是这么称呼. 转发一篇文章 http://www.cnblogs.com/zhangkai5157/p/3289532.html

  5. 【JAVA、C++】LeetCode 013 Roman to Integer

    Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 t ...

  6. Eclipse调试:F5、F6、F7、F8

    F5:跳入方法 F6:向下逐行调试 F7:跳出方法 F8:直接跳转到下一个断点 转载自:http://blog.sina.com.cn/s/blog_6271df6f0101d856.html

  7. CodeForces - 405A

    Gravity Flip Time Limit: 1000MS   Memory Limit: 262144KB   64bit IO Format: %I64d & %I64u Submit ...

  8. 2016国产开源软件TOP100(Q1)

    随着互联网的发展.开放标准的普及和虚拟化技术的应用等诸多IT新领域的创新及拓展,开源技术凭借其开放性.低成本.稳定性.灵活性.安全性和技术创新性等特点迅速走向成熟,逐步发展成为一种主流模式,日益改变着 ...

  9. jquery easy ui 1.3.4 表单(7)

    7.1.ValidateBox(表单验证) 使用validType属性指定验证方法 1.标签方式创建 <input type="text" class="easyu ...

  10. mac安装nginx

    1,http://nginx.org/en/download.html下载http://nginx.org/download/nginx-1.2.0.tar.gz 2,tar -xf nginx-1. ...