【费用流】疯狂的方格取数 vijos 1653
来源:互联网 发布:黑客论坛源码 编辑:程序博客网 时间:2024/06/04 22:47
背景
Due to the talent of talent123,当talent123做完NOIP考了两次的二取方格数和vijos中的三取方格数后,突发奇想....
描述
在一个宽M,长N的矩阵中,请你编一个程序,n次从矩阵的左上角走到矩阵的右下角,每到一处,就取走该处的数字,请你选择一
种走法使取得的数字的和最大,并输出其最大值。其中:3<=M<=20 M<=N<=100 1<=n<=10
如输入数据:
3 10 13
0 1 2 3 4 9 7 1 3 1
9 1 2 2 3 6 7 8 1 2
1 2 3 4 5 9 8 7 6 1
9 7 1 3 1 9 1 2 2 3
6 7 8 1 2 1 2 3 4 5
9 1 2 2 3 6 7 8 1 2
1 2 3 4 5 9 8 7 6 1
9 7 1 3 1 9 1 2 2 3
6 7 8 1 2 1 2 3 4 5
9 1 2 2 3 6 7 8 1 2
1 2 3 4 5 9 8 7 6 1
9 7 1 3 1 9 1 2 2 3
6 7 8 1 2 1 2 3 4 0
其中n=3
M=10
N=13
即当n=3时,就相当于是3取方格数。
对于以上的数据:
将输出:297
//注:如过你想到了无记忆性搜所的方法(不管你怎样优化),你可以直接放弃这道题了。
//提示1:动态规划如果用的是二位数组,规模为100*100000即可。
//提示2:如果你坚信自己的程序已经无可优化了,可有2个数据依然超时,那么告诉你,存在数据有M<n的情况!!!
格式
输入格式
第一行:三个整数:n M N
以下的N行每行M个数字,代表你要处理的矩阵。
输出格式
只有一行:你所取得的数字的和。
样例1
样例输入1
4 6 70 2 3 4 5 66 5 4 3 2 10 9 8 7 6 512 3 4 5 6 70 0 0 1 2 312 23 34 45 1 234 5 6 6 1 0
样例输出1
265
这一题是很经典的费用流题目,加入一个超级源到第一个点,费用为0,流量为K
同样加入超级汇
把每个点拆成两个点(如点和出点),入点和出点之间连一条流量为1和费用为权值的边,再连一条流量为inf,费用为0的点,这就表示每个点只能取一次,但是可以重复走了
然后再把整个图连起来
跑一次费用流,ok~
第一次写邻接表式的费用流,调了很久
测评情况(Vijos)
/*http://blog.csdn.net/jiangzh7By Jiangzh*/#include<cstdio>#include<cstring>#include<queue>using namespace std;const int N=100+10;const int P=N*N*5;const int inf=0x3f3f3f3f;int n,m,K;int map[N][N];struct EG{int from,to,flow,cost,next;}edge[P];int head[P],L;int S,T;bool inQ[P];int dist[P];int pre[P];queue<int> Q;void read(){scanf("%d%d%d",&K,&m,&n);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%d",&map[i][j]);}inline int In (int x,int y) { return ((x-1)*m+y)*2-1; }inline int Out(int x,int y) { return ((x-1)*m+y)*2; }void add_edge(int x,int y,int z,int w){edge[L]=(EG){x,y,z,w ,head[x]};head[x]=L++;edge[L]=(EG){y,x,0,-w,head[y]};head[y]=L++;}void make_map(){memset(head,-1,sizeof(head));for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){add_edge(In(i,j),Out(i,j),1,map[i][j]);add_edge(In(i,j),Out(i,j),inf,0);if(j<m) add_edge(Out(i,j),In(i,j+1),inf,0);if(i<n) add_edge(Out(i,j),In(i+1,j),inf,0);}S=0;T=Out(n,m)+1;add_edge(S,In(1,1),K,0);add_edge(Out(n,m),T,inf,0);}bool spfa(){for(int i=S;i<=T;i++) dist[i]=-inf;memset(inQ,0,sizeof(inQ));dist[S]=0;Q.push(S);while(!Q.empty()){int x=Q.front();Q.pop();inQ[x]=false;for(int i=head[x];i!=-1;i=edge[i].next){if(edge[i].flow>0 && dist[edge[i].to]<dist[x]+edge[i].cost){pre[edge[i].to]=i;dist[edge[i].to]=dist[x]+edge[i].cost;if(!inQ[edge[i].to]){inQ[edge[i].to]=true;Q.push(edge[i].to);}}}}return dist[T]!=-inf;}void work(){make_map();memset(pre,-1,sizeof(pre));int maxcost=0,maxflow=0;while(spfa()){int res=inf;for(int i=T;i!=S;i=edge[pre[i]^1].to){res=min(res,edge[pre[i]].flow);}for(int i=T;i!=S;i=edge[pre[i]^1].to){edge[pre[i]].flow-=res;edge[pre[i]^1].flow+=res;}maxflow+=res;maxcost+=res*dist[T];}printf("%d\n",maxcost);}int main(){freopen("vijos1653.in","r",stdin);freopen("vijos1653.out","w",stdout);read();work();return 0;}
- 【费用流】疯狂的方格取数 vijos 1653
- [最大费用最大流] [记忆化搜索] [Vijos P1653] 疯狂的方格取数 (getnum)
- 【费用流】codevs1227 方格取数 2
- 【codevs1227】方格取数2,费用流
- codevs1227(方格取数费用流)
- Codevs 1227方格取数 (费用流
- 1227 方格取数 2 费用流
- VIJOS 1143 三方格取数
- Vijos -- 1143 三取方格数
- vijos P1143三取方格数
- 【codevs1227】方格取数2 费用流(EK)
- 【CODEVS1227】方格取数2(费用流)
- Codevs 1227 方格取数2 [费用流] [拆点]
- 【codevs 1227】方格取数2(费用流)
- Codevs 1227 方格取数 2(费用流)
- 洛谷 P2045 方格取数加强版 (费用流)
- Codevs[1227]方格取数2 费用流
- wiki 方格取数2 网络流 最大流最小费用流
- 设计模式学习系列十五:访问者模式(Visitor)
- [3月5日的脚本] 从csv文件中大批量导入用户信息
- md5加密算法c实现
- 简单工厂、工厂方法、抽象工厂之小结与区别
- Linux下Json库的编译及代码测试
- 【费用流】疯狂的方格取数 vijos 1653
- 正则表达式, 小数点后两位
- 图的设计与实现
- 【2014】计算机已知统考和非统考学校信息汇总(比较全)
- Java synchronized详解
- 栈代码
- 编程珠玑 第一章习题解答
- 拷贝构造函数
- Ext apiDoc 离线版制作