[恢复状态] Gym 100202F
感谢@似水流年 的翻译
感谢@FizzyDavid 的提示
题意:
你可以横着刷一串,代价是h;竖着一串代价是v,单独刷一格代价是s
第一眼看起来是什么奇怪的技巧
思考了半天不会...
后来想到网络流,推不出来很抓狂
今天仔细推了一下终于出来了...
最小割即可
S集合:s点源点 所有选的行 没选的列
T集合:t点汇点 所有选的列 没选的行
自然,选某一行的代价是有的, 行-->t 一条有向边代价为h
同理,选某一列的代价是有的, s-->列 一条有向边代价为v
还有,行列都不选,意味着它要单独刷,列-->行 一条有向边代价为c(没选的列-->没选的行要割掉)
这样图就建出来了
之后,求最小割只需要bfs一遍所有从s能到的点都是S集合....
结束....
代码又是250行
#include<set>
#include<map>
#include<list>
#include<queue>
#include<stack>
#include<math.h>
#include<string>
#include<time.h>
#include<bitset>
#include<vector>
#include<memory>
#include<utility>
#include<stdio.h>
#include<sstream>
#include<fstream>
#include<iostream>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=2005;
const int inf=999999999;
struct edge
{
int y;
int weight;
edge * next;
edge * anti;
};
edge * li[maxn];
edge * new_edge()
{
static edge a[30005];
static int top=0;
return &a[top++];
}
edge * inserts(int x,int y,int z)
{
edge * t=new_edge();
t->y=y;
t->weight=z;
t->next=li[x];
li[x]=t;
return t;
}
void insert_edge(int x,int y,int z)
{
edge * t1=inserts(x,y,z);
edge * t2=inserts(y,x,0);
t1->anti=t2;
t2->anti=t1;
}
int dist[maxn];
bool bfs(int s,int t)
{
memset(dist,-1,sizeof(dist));
static int que[maxn];
int front=0,rail=1;
que[0]=s;
dist[s]=0;
for (;front<rail;front++)
{
int now=que[front];
edge * x;
for (x=li[now];x!=0;x=x->next)
{
if ((x->weight>0)&&(dist[x->y]==-1))
{
dist[x->y]=dist[now]+1;
if (x->y==t) return 1;
que[rail++]=x->y;
}
}
}
return 0;
}
int max_flow(int s,int t)
{
int tot=0;
static int pre[maxn];
static edge * cur[maxn];
static edge * path[maxn];
for (;bfs(s,t);)
{
memcpy(cur,li,sizeof(cur));
int now=s;
for (;dist[s]!=-1;)
{
if (now==t)
{
int min_ans=inf;
int temp;
for (temp=t;temp!=s;temp=pre[temp])
{
min_ans=min(min_ans,path[temp]->weight);
}
tot+=min_ans;
for (temp=t;temp!=s;temp=pre[temp])
{
path[temp]->weight-=min_ans;
path[temp]->anti->weight+=min_ans;
}
now=s;
}
edge * x;
for (x=cur[now];x!=0;x=x->next)
{
if ((x->weight!=0)&&(dist[x->y]==dist[now]+1))
{
path[x->y]=x;
pre[x->y]=now;
cur[now]=x;
now=x->y;
break;
}
}
if (x==0)
{
dist[now]=-1;
now=pre[now];
}
}
}
return tot;
}
char a[35][35];
int belong_to[35][35];
int belong_2[35][35];
int n,m;
void find(int x)
{
int i,j;
int minx=n,miny=m,maxx=0,maxy=0;
char y;
for (i=0;i<n;i++)
{
for (j=0;j<m;j++)
{
if ((belong_to[i][j]==x)||(belong_2[i][j]==x))
{
minx=min(minx,i);
maxx=max(maxx,i);
miny=min(miny,j);
maxy=max(maxy,j);
y=a[i][j];
}
}
}
printf("%d %d %d %d %c\n",minx+1,miny+1,maxx+1,maxy+1,y);
}
int main()
{
freopen("painter.in","r",stdin);
freopen("painter.out","w",stdout);
scanf("%d%d",&n,&m);
int h,v,c;
scanf("%d%d%d",&h,&v,&c);
int i;
for (i=0;i<n;i++)
{
scanf("%s",a[i]);
}
int s=0,t=1;
int sum=2;
for (i=0;i<n;i++)
{
int j;
for (j=0;j<m;j++)
{
belong_to[i][j]=sum;
if (a[i][j]!=a[i][j+1])
{
insert_edge(sum,t,h);
sum++;
}
}
}
int x=sum;
for (i=0;i<m;i++)
{
int j;
for (j=0;j<n;j++)
{
belong_2[j][i]=sum;
insert_edge(sum,belong_to[j][i],c);
if (a[j][i]!=a[j+1][i])
{
insert_edge(s,sum,v);
sum++;
}
}
}
printf("%d ",max_flow(s,t));
int tot=0;
for (i=2;i<x;i++)
{
if (dist[i]!=-1)
{
tot++;
}
}
for (;i<sum;i++)
{
if (dist[i]==-1)
{
tot++;
}
}
for (i=0;i<n;i++)
{
int j;
for (j=0;j<m;j++)
{
if ((dist[belong_to[i][j]]==-1)&&(dist[belong_2[i][j]]!=-1))
{
tot++;
}
}
}
printf("%d\n",tot);
for (i=2;i<x;i++)
{
if (dist[i]!=-1)
{
printf("h ");
find(i);
}
}
for (;i<sum;i++)
{
if (dist[i]==-1)
{
printf("v ");
find(i);
}
}
for (i=0;i<n;i++)
{
int j;
for (j=0;j<m;j++)
{
if ((dist[belong_to[i][j]]==-1)&&(dist[belong_2[i][j]]!=-1))
{
printf("s %d %d %c\n",i+1,j+1,a[i][j]);
}
}
}
return 0;
}
评论 (0)