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
Case 1 : 0 Case 2 : 15 Case 3 : 16 Case 4 : 18 Case 5 : -1
官方题解:
最小K路径覆盖的模型,用费用流或者KM算法解决,构造二部图,X部有N*M个节点,源点向X部每个节点连一条边,流量1,费用0,Y部有N*M个节点,每个节点向汇点连一条边,流量1,费用0,如果X部的节点x可以在一步之内到达Y部的节点y,那么就连边x->y,费用为从x格子到y格子的花费能量减去得到的能量,流量1,再在X部增加一个新的节点,表示可以从任意节点出发K次,源点向其连边,费用0,流量K,这个点向Y部每个点连边,费用0,流量1,最这个图跑最小费用最大流,如果满流就是存在解,反之不存在,最小费用的相反数就是可以获得的最大能量
可以这样考虑,首先建立一个二分图,在x部内的可以到达y部的点建边<u,v>;首先求得该二部图的最小路径覆盖=节点总数-最大流;(最小路径覆盖:用最少的路径覆盖住所有的节点,且每个节点只能在一条路径上),加入k值小于最小的路径数目,那么肯定是在k次之内是不可能完成任务的。
所以这样建图之后求得是原先的最大流+k,若最大流+k<n*m则无解,输出-1,否则求出的最小费用的相反数就是最大能量。
程序;
#include"stdio.h" #include"string.h" #include"iostream" #include"map" #include"string" #include"queue" #include"stdlib.h" #include"math.h" #define M 333 #define eps 1e-10 #define inf 1000000000 #define mod 2333333 using namespace std; struct node { int u,v,w,cost,next; }edge[M*M*3]; int t,head[M],dis[M],use[M],pre[M],Max_flow,Min_cost,top[M],q[M],work[M]; void init() { t=0; memset(head,-1,sizeof(head)); } void add(int u,int v,int w,int cost) { edge[t].u=u; edge[t].v=v; edge[t].w=w; edge[t].cost=cost; edge[t].next=head[u]; head[u]=t++; edge[t].u=v; edge[t].v=u; edge[t].w=0; edge[t].cost=-cost; edge[t].next=head[v]; head[v]=t++; } int min_flow(int S,int T) { int ans=0; Max_flow=0; while(1) { int i; queue<int>q; for(i=0;i<=T+1;i++) dis[i]=inf; dis[S]=0; memset(use,0,sizeof(use)); memset(pre,-1,sizeof(pre)); q.push(S); while(!q.empty()) { int u=q.front(); use[u]=0; q.pop(); for(i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].v; if(edge[i].w&&dis[v]>dis[u]+edge[i].cost) { dis[v]=dis[u]+edge[i].cost; pre[v]=i; if(!use[v]) { use[v]=1; q.push(v); } } } } if(dis[T]==inf) break; int Min=inf+1; for(i=pre[T];i!=-1;i=pre[edge[i].u]) { Min=min(Min,edge[i].w); } for(i=pre[T];i!=-1;i=pre[edge[i].u]) { edge[i].w-=Min; edge[i^1].w+=Min; } Max_flow+=Min; ans+=Min*dis[T]; } return ans; } int num[22][22],mp[22][22]; char Mp[22][22]; int main() { int T,kk=1; scanf("%d",&T); while(T--) { int n,m,k,i,j,r; scanf("%d%d%d",&n,&m,&k); int cnt=0; init(); for(i=1;i<=n;i++) { scanf("%s",Mp[i]); for(j=1;j<=m;j++) { mp[i][j]=Mp[i][j-1]-'0'; num[i][j]=++cnt; } } for(i=1;i<=m*n;i++) { add(0,i,1,0); add(i+m*n,m*n*2+1,1,0); } for(i=1;i<=n;i++) { for(j=1;j<=m;j++) { int Cost; for(r=j+1;r<=m;r++) { if(mp[i][j]==mp[i][r]) Cost=r-j-1-mp[i][j]; else Cost=r-j-1; add(num[i][j],num[i][r]+m*n,1,Cost); } for(r=i+1;r<=n;r++) { if(mp[i][j]==mp[r][j]) Cost=r-i-1-mp[i][j]; else Cost=r-i-1; add(num[i][j],num[r][j]+m*n,1,Cost); } } } for(i=n*m+1;i<=m*n*2;i++) add(m*n*2+2,i,1,0); add(0,m*n*2+2,k,0); Min_cost=min_flow(0,m*n*2+1); printf("Case %d : ",kk++); if(Max_flow!=n*m) { printf("-1\n"); continue; } printf("%d\n",-Min_cost); } }