Jump
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1436 Accepted Submission(s): 610
Total Submission(s): 1436 Accepted Submission(s): 610
Problem Description
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.
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.
Input
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)
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)
Output
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.
Sample Input
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
Sample Output
Case 1 : 0 Case 2 : 15 Case 3 : 16 Case 4 : 18 Case 5 : -1
题意:给你一个n*m的矩阵,你可以从选择任何一个点,从这个点向下和向右跳(可空格跳),跳的次数不做限制,同一个点不能跳两次跳的两点间的消耗曼哈顿距离-1能量,若两点数字相同,则怎加数字的能量值,问在不超过k次选择点,能到达所有点的最大能量值。
思路:
很明显的最小费用流,同一个点只能跳一次,明显要拆点。关键在于到达所有的点应该如何在图中表示。
1.首先要定义一个起点(初始位置的集合),源点点到这个起点的流量为k.
2.起点连接点的右点,流量为1,花费0;
3.起点连接每个点的左点,流量为1,花费0;
4.能到达的点连接,流量1,花费算一下就好;
5.每个点右点连接汇点,流量为1.
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#define inf 0x7fffffff
using namespace std;
typedef long long ll;
const int maxn=1111;
int n,m,from,to;
struct node
{
int v,flow,cost;
int next;
} edge[maxn*40];
int head[maxn],edgenum;
ll dis[maxn],pre[maxn],pid[maxn],vis[maxn];
char num[maxn][maxn];
int t;
void add(int u,int v,int flow,int cost)
{
edge[edgenum].v=v ;
edge[edgenum].flow=flow ;
edge[edgenum].cost=cost ;
edge[edgenum].next=head[u];
head[u]=edgenum++;
edge[edgenum].v=u ;
edge[edgenum].flow=0;
edge[edgenum].cost=-cost ;
edge[edgenum].next=head[v];
head[v]=edgenum++;
}
ll spfa()
{
for (int i=0 ; i<=to ; i++)
{
dis[i]=-inf;
vis[i]=0;
}
queue<int> Q;
Q.push(from);
dis[from]=0;
vis[from]=1;
while (!Q.empty())
{
int u=Q.front() ;
Q.pop() ;
vis[u]=0;
for (int i=head[u] ; i!=-1 ; i=edge[i].next)
{
int v=edge[i].v;
if (edge[i].flow>0 && dis[v]<dis[u]+edge[i].cost)
{
dis[v]=dis[u]+edge[i].cost;
pre[v]=u;
pid[v]=i;
if (!vis[v])
{
vis[v]=1;
Q.push(v);
}
}
}
}
return dis[to];
}
int mincost()
{
int aug=0,maxflow=0;
ll ans=0,tmp=0;
while (1)
{
tmp=spfa();
if (tmp==-inf) break;
aug=inf;
for (int i=to ; i!=from ; i=pre[i])
{
if (edge[pid[i] ].flow<aug)
aug=edge[pid[i] ].flow;
}
for (int i=to ; i!=from ; i=pre[i])
{
edge[pid[i] ].flow -= aug;
edge[pid[i]^1 ].flow += aug;
}
maxflow += aug;
ans += tmp;
}
if(maxflow!=n*m)
printf("Case %d : -1\n",t);
else
printf("Case %d : %I64d\n",t,ans);
}
int main()
{
int k;
int T;
scanf("%d",&T);
for(t=1;t<=T;t++)
{
memset(head,-1,sizeof(head));
edgenum=0;
scanf("%d%d%d",&n,&m,&k);
for(int i=0;i<n;i++)
scanf("%s",num[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
num[i][j]-='0';
}
from=0;
to=n*m*2+2;
int bin=n*m*2+1;
add(0,bin,k,0);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
add(0,i*m+j+1,1,0);
add(bin,i*m+j+1+n*m,1,0);
add(i*m+j+1+n*m,to,1,0);
for(int kk=i+1;kk<n;kk++)
{
if(num[i][j]==num[kk][j])
add(i*m+j+1,kk*m+j+1+n*m,1,i+1-kk+num[i][j]);
else
add(i*m+j+1,kk*m+j+1+n*m,1,i+1-kk);
}
for(int kk=j+1;kk<m;kk++)
{
if(num[i][j]==num[i][kk])
add(i*m+j+1,i*m+kk+1+n*m,1,j+1-kk+num[i][j]);
else
add(i*m+j+1,i*m+kk+1+n*m,1,j+1-kk);
// printf("%d %d ~%d~\n",num[i][j],num[i][kk],j+1-kk+num[i][j]);
}
}
mincost();
}
return 0;
}