hdu4862Jump【最大费用最大流,判断是否满流】2014多校联合
2016-06-24 17:04
405 查看
JumpTime Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1275 Accepted Submission(s): 547 [align=left]Problem Description[/align] There are n*m grids, each grid contains a number, ranging from 0-9. Your initial energy is zero. You can play up to K times the game, every time you can choose any one of the grid as a starting point (but not traveled before) then you can choose a grid on the right or below the current grid to jump, but it has not traveled before. Every time you can jump as many times as you want, as long as you do not violate rules. If you are from (x1, y1) to (x2, y2), then you consume |x1-x2|+|y1-y2|-1 energies. Energy can be negative. However, in a jump, if you start position and end position has same numbers S, then you can increase the energy value by S. Give me the maximum energy you can get. Notice that you have to go each grid exactly once and you don’t have to play exactly K times. [align=left]Input[/align] The first line is an integer T, stands for the number of the text cases. Then T cases followed and each case begin with three numbers N, M and K. Means there are N rows and M columns, you have K times to play. Then N lines follow, each line is a string which is made up by M numbers. The grids only contain numbers from 0 to 9. (T<=100, N<=10,M<=10,K<=100) [align=left]Output[/align] Each case, The first you should output “Case x : ”,(x starting at 1),then output The maximum number of energy value you can get. If you can’t reach every grid in no more than K times, just output -1. [align=left]Sample Input[/align] 5 1 5 1 91929 1 5 2 91929 1 5 3 91929 3 3 3 333 333 333 3 3 2 333 333 333 [align=left]Sample Output[/align] Case 1 : 0 Case 2 : 15 Case 3 : 16 Case 4 : 18 Case 5 : -1 [align=left]Author[/align] FZU [align=left]Source[/align] 2014 Multi-University Training Contest 1 [align=left]Recommend[/align] We have carefully selected several similar problems for you: 5717 5716 5715 5714 5713 |
说题意,给出n*m的数据,选择k条不重复的道路,起点终点任意,但是需要保证每个点都要走到,每步只能选择右边或者下边的点(即,只能竖着往下走或者横着往右走,不可以斜着往右下走)每步的费用是+(ii-i+jj-j-1)-(num[i][j]==num[ii][jj]?num[i][j]:0)
很容易想到用网络流控制流量,用费用流控制费用(好像说的是废话==),既然要要求每个点都走,有了流量控制,就一定要拆点。那么就拆成了x部,y部。很容易想到从s到x每个点cap=1 cost=0,y到t每个点cap=1 cost=0,x到可行的y cap=1 cost=题目已知的值(注意是相反数)然而k要如何限制?再加一个S',S->S'
cap=k cost=0,S'到Y的每个点cap=1 cost=0。
为什么这么建边就可以保证了呢?这样可以保证不会先选S'->Y
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int oo=0x3f3f3f3f;//无穷大
const int maxm=11111;//边的最大数量,为原图的两倍
const int maxn=222;//点的最大数量
int node,src,dest,edge;//node节点数,src源点,dest汇点,edge边数
int head[maxn],p[maxn],dis[maxn],q[maxn],vis[maxn];//head链表头,p记录可行流上节点对应的反向边,dis计算距离
int n,m,k;
struct edgenode
{
int to;//边的指向
int flow;//边的容量
int cost;//边的费用
int next;//链表的下一条边
} edges[maxm];
void prepare(int _node,int _src,int _dest);
void addedge(int u,int v,int f,int c);
bool spfa();
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;
vis[i]=false;
}
edge=0;
}
void addedge(int u,int v,int f,int c)
{
edges[edge].flow=f;
edges[edge].cost=c;
edges[edge].to=v;
edges[edge].next=head[u];
head[u]=edge++;
edges[edge].flow=0;
edges[edge].cost=-c;
edges[edge].to=u;
edges[edge].next=head[v];
head[v]=edge++;
}
bool spfa()
{
int i,u,v,l,r=0,tmp;
for (i=0; i<node; i++) dis[i]=oo;
dis[q[r++]=src]=0;
p[src]=p[dest]=-1;
for (l=0; l!=r; ((++l>=maxn)?l=0:1))
{
for (i=head[u=q[l]],vis[u]=false; i!=-1; i=edges[i].next)
{
if (edges[i].flow&&dis[v=edges[i].to]>(tmp=dis[u]+edges[i].cost))
{
dis[v]=tmp;
p[v]=i^1;
if (vis[v]) continue;
vis[q[r++]=v]=true;
if (r>=maxn) r=0;
}
}
}
return p[dest]>=0;
}
int spfaflow()
{
int i,ret=0,delta,sum=0;
while (spfa())
{
//按记录原路返回求流量
for (i=p[dest],delta=oo; i>=0; i=p[edges[i].to])
{
delta=min(delta,edges[i^1].flow);
}
for (int i=p[dest]; i>=0; i=p[edges[i].to])
{
edges[i].flow+=delta;
edges[i^1].flow-=delta;
}
sum+=delta;//流量
ret+=delta*dis[dest];
}
// printf("sum=%d ",sum);
// printf("n=%d,m=%d\n",n,m);
if(sum!=n*m)return 1;
return ret;
}
int num[20][20],b[20][20];
int main()
{
// freopen("cin.txt","r",stdin);
int t,cas=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
// printf("n=%d,m=%d\n",n,m);
for(int i=0;i<n;i++)
{
char tmp[20];
scanf("%s",tmp);
for(int j=0;j<m;j++)
num[i][j]=tmp[j]-'0';
}
//for(int i=0;i<n;i++)for(int j=0;j<m;j++)printf("%d ",num[i][j]);
prepare(2*n*m+3,2*n*m,2*n*m+2);
addedge(2*m*n,2*m*n+1,k,0);
for(int i=0;i<n;i++)
{
for(int j=0;j<m;j++)
{
int u=j+i*m;
addedge(2*n*m,u,1,0);
addedge(u+n*m,n*m*2+2,1,0);
addedge(2*m*n+1,u+n*m,1,0);
for(int ii=i+1;ii<n;ii++)
{
for(int jj=j;jj<=j;jj++)
{
if(i==ii&&j==jj)continue;
int uu=jj+ii*m+n*m;
int tmp=num[i][j]==num[ii][jj]?num[i][j]:0;
addedge(u,uu,1,+(ii-i+jj-j-1)-tmp);
}
}
for(int ii=i;ii<=i;ii++)
{
for(int jj=j+1;jj<m;jj++)
{
if(i==ii&&j==jj)continue;
int uu=jj+ii*m+n*m;
int tmp=num[i][j]==num[ii][jj]?num[i][j]:0;
addedge(u,uu,1,+(ii-i+jj-j-1)-tmp);
}
}
}
}
printf("Case %d : %d\n",cas++,-spfaflow());
}
return 0;
}
相关文章推荐
- Elasticsearch安装配置
- CSS布局 ——从display,position, float属性谈起
- 再谈让C++更像C#:C#内存泄露问题
- VC下release版本和Debug版本的区别及各自的特点
- 一、导出类的简单方式
- vim环境设置和自动对齐
- JS组件系列——Bootstrap组件福利篇:几款好用的组件推荐
- 测试报告的模板
- 工厂方法模式(Factory Method)
- Redis之CentOS7安装
- 《操作系统》-实验四主存空间的分配和回收
- 开源内容管理系统Joomla正式发布3.5版本 基于PHP 7
- Java正则表达式基础案例和语法
- 长尾关键词的优化方法
- nmap参数详解及使用方法
- 结构体定义:struct与typedef struct 用法详解和用法小结
- 基于朴素贝叶斯的文本分类器
- mysql-数据库的更新和删除
- Android初步笔记
- 嵌入式操作系统概述