[费用流]BZOJ:3171: [Tjoi2013]循环格

本文介绍了一道Tjoi2013竞赛中的循环格题目,探讨了如何通过构造类似二分图的方法来解决该问题,并采用最小费用最大流算法寻找最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

3171: [Tjoi2013]循环格

Time Limit: 1 Sec   Memory Limit: 128 MB
Submit: 258   Solved: 153
[ Submit][ Status]

Description

Input

第一行两个整数R,C。表示行和列,接下来R行,每行C个字符LRUD,表示左右上下。

Output

 

一个整数,表示最少需要修改多少个元素使得给定的循环格完美

Sample Input

3 4
RRRD
URLL
LRRR

Sample Output

2

HINT

1<=R,L<=15

Source

首先,我们可以推断出来:构成循环格的条件是每个格子入度出度都是1
那么我们可以构造一个类似二分图的图,左边右边点相同,如果i可以指到j,左i到右j连一条边
这样每个格子都有一个入边和出边了
然后是费用的问题,如果存在边(左i,右j)如果i原本就指向j,则cost[i][j]=0,否则为1
然后求最小费用最大流
/**************************************************************
    Problem: 3171
    User: SKYDEC
    Language: C++
    Result: Accepted
    Time:268 ms
    Memory:4712 kb
****************************************************************/
 
#include<stdio.h>
#define f(i,j) ((i)-1)*c+(j)
#define debug printf("yeah!")
using namespace std;
bool create[800][800];
long cost[800][800];
long pre[500];long r,c,s,t;
long que[100000],k[100000];
int spfa()
{
    pre[t]=-1;bool gone[500]={false};que[0]=1;que[1]=s;gone[s]=true;long dis[800];for(long i=s;i<=t;i++)dis[i]=2100000000;
    dis[0]=0;
    while(que[0]!=0)
    {
        k[0]=0;
        for(long i=1;i<=que[0];i++)
        {
            long cur=que[i];
            for(long j=s;j<=t;j++)
            if(create[cur][j]&&(dis[cur]+cost[cur][j]<dis[j]))
            {
                dis[j]=dis[cur]+cost[cur][j];pre[j]=cur;
                if(!gone[j]){k[++k[0]]=j;gone[j]=true;}
            }
            gone[cur]=false;
        }
        que[0]=k[0];for(long u=1;u<=que[0];u++)que[u]=k[u];
    }
    return pre[t];
}
int main()
{
    //freopen("grid.in","r",stdin);freopen("grid.out","w",stdout);
    scanf("%ld%ld",&r,&c);s=0;t=2*r*c+1;char goe;scanf("%c",&goe);
    for(long i=1;i<=r;i++)for(long j=1;j<=c;j++)
    {
        create[s][f(i,j)]=true;create[f(i,j)+r*c][t]=true;
        create[f(i,j)][f(i,j%c+1)+r*c]=true;
	cost[f(i,j)][f(i,j%c+1)+r*c]=1;
	cost[f(i,j%c+1)+r*c][f(i,j)]=-1;
        create[f(i,j)][f(i%r+1,j)+r*c]=true;
	cost[f(i,j)][f(i%r+1,j)+r*c]=1;
	cost[f(i%r+1,j)+r*c][f(i,j)]=-1;
        long ti=i,tj=j;if(i==1)ti=r;else ti--;
        create[f(i,j)][f(ti,tj)+r*c]=true;
	cost[f(i,j)][f(ti,tj)+r*c]=1;
	cost[f(ti,tj)+r*c][f(i,j)]=-1;
        ti=i;tj=j;if(j==1)tj=c;else tj--;
        create[f(i,j)][f(ti,tj)+r*c]=true;
	cost[f(i,j)][f(ti,tj)+r*c]=1;
	cost[f(ti,tj)+r*c][f(i,j)]=-1;
    }
    for(long i=1;i<=r;i++)
    {
        for(long j=1;j<=c;j++)
        {
            char u;scanf("%c",&u);
            if(u=='R')cost[f(i,j)][f(i,j%c+1)+r*c]=cost[f(i,j%c+1)+r*c][f(i,j)]=0;
            if(u=='D')cost[f(i,j)][f(i%r+1,j)+r*c]=cost[f(i%r+1,j)+r*c][f(i,j)]=0;
            if(u=='U')
            {
                long ti=i,tj=j;if(i==1)ti=r;else ti--;
                cost[f(i,j)][f(ti,tj)+r*c]=cost[f(ti,tj)+r*c][f(i,j)]=0;
            }
            if(u=='L')
            {
                long ti=i,tj=j;if(j==1)tj=c;else tj--;
                cost[f(i,j)][f(ti,tj)+r*c]=cost[f(ti,tj)+r*c][f(i,j)]=0;
            }
        }
        while(true)
        {
            scanf("%c",&goe);
            if(goe=='\n')break;
        }
    }
    long long ans=0;
    while(spfa()!=-1)
    {
        long p=t;
        while(p!=s)
        {
            ans+=cost[pre[p]][p];
            create[pre[p]][p]=false;
            create[p][pre[p]]=true;
            p=pre[p];
        }
    }
    printf("%lld",ans);
    //for(;;);
    return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值