HAOI2008 移动玩具

题目链接:戳我

非常抱歉,菜鸡风浔凌又来水蓝题了qwq

看到题解上写双向搜索???什么鬼.......

看到数据范围特别小,直接划分二分图,两个点之间连接容量为1,费用为曼哈顿距离的边,跑费用流即可。

什么?你问我那个不能移动到有玩具的格子的限制?

不用管了啦,因为费用流会给你跑费用最小的,也就是每个点都会找到最近的那个点,不会有其他点和它抢位置的。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define S 0
#define T tot1+tot2+1
#define MAXN 110
using namespace std;
int n,m,tot1,tot2,t=1,c,f;
int pre_e[MAXN],pre_v[MAXN];
int a[MAXN][MAXN],b[MAXN][MAXN],head[MAXN],dis[MAXN],done[MAXN];
int move_x[4]={0,0,1,-1},move_y[4]={1,-1,0,0};
struct Node{int x,y,id;}node1[MAXN],node2[MAXN];
struct Edge{int nxt,to,dis,cost;}edge[100010];
inline void add(int from,int to,int dis,int cost)
{
    edge[++t].nxt=head[from],edge[t].to=to,edge[t].dis=dis,edge[t].cost=cost,head[from]=t;
    edge[++t].nxt=head[to],edge[t].to=from,edge[t].dis=0,edge[t].cost=-cost,head[to]=t;
}
inline bool spfa()
{
    queue<int>q;
    memset(dis,0x3f,sizeof(dis));
    memset(done,0,sizeof(done));
    q.push(S);done[S]=1;dis[S]=0;
    while(!q.empty())
    {
        int u=q.front();q.pop();done[u]=0;
        for(int i=head[u];i;i=edge[i].nxt)
        {
            int v=edge[i].to;
            if(edge[i].dis&&dis[u]+edge[i].cost<dis[v])
            {
                dis[v]=dis[u]+edge[i].cost;
                pre_e[v]=i,pre_v[v]=u;
                if(!done[v])
                    q.push(v),done[v]=1;
            }
        }
    }
    if(dis[T]>=0x3f3f3f3f) return false;
    int flow=0x3f3f3f3f;
    for(int i=T;i!=S;i=pre_v[i]) flow=min(flow,edge[pre_e[i]].dis);
    for(int i=T;i!=S;i=pre_v[i]) edge[pre_e[i]].dis-=flow,edge[pre_e[i]^1].dis+=flow;
    f+=flow;
    c+=flow*dis[T];
    return true;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            scanf("%1d",&a[i][j]);
            if(a[i][j]==1) node1[++tot1]=(Node){i,j,tot1};
        }
    for(int i=1;i<=4;i++)
        for(int j=1;j<=4;j++)
        {
            scanf("%1d",&b[i][j]);
            if(b[i][j]==1) node2[++tot2]=(Node){i,j,tot2};
        }
    // printf("tot1=%d tot2=%d\n",tot1,tot2);
    for(int i=1;i<=tot1;i++) add(S,node1[i].id,1,0);
    for(int i=1;i<=tot2;i++) add(node2[i].id+tot1,T,1,0);
    for(int i=1;i<=tot1;i++)
    {
        for(int j=1;j<=tot2;j++)
        {
            add(node1[i].id,node2[j].id+tot1,1,abs(node1[i].x-node2[j].x)+abs(node1[i].y-node2[j].y));
        }
    }
    while(spfa());
    printf("%d\n",c);
    return 0;
}

原文地址:https://www.cnblogs.com/fengxunling/p/10909267.html

时间: 2024-10-05 05:04:36

HAOI2008 移动玩具的相关文章

BZOJ1054: [HAOI2008]移动玩具

1054: [HAOI2008]移动玩具 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1028  Solved: 555[Submit][Status] Description 在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到某人心中的目标状态. Input 前4行表示玩具的初始状态,每行4个

BZOJ 1054: [HAOI2008]移动玩具( BFS )

一开始没有注意答案为0的情况然后就WA了... 挺水的BFS.. ------------------------------------------------------------------------------ #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cctype> #include<iostream>

【bzoj1054】[HAOI2008]移动玩具

题目描述 在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到某人心中的目标状态. 输入 前4行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具.接着是一个空行.接下来4行表示玩具的目标状态,每行4个数字1或0,意义同上. 输出 一个整数,所需要的最少移动次数. 样例输入 1111 0000 1110 0010 1

【HAOI2008】玩具命名

水题大失败 原题: 某人有一套玩具,并想法给玩具命名.首先他选择WING四个字母中的任意一个字母作为玩具的基本名字.然后他会根据自己的喜好,将名字中任意一个字母用"WING"中任意两个字母代替,使得自己的名字能够扩充得很长.现在,他想请你猜猜某一个很长的名字,最初可能是由哪几个字母变形过来的. 第一行四个整数W.I.N.G.表示每一个字母能由几种两个字母所替代.接下来W行,每行两个字母,表示W可以用这两个字母替代.接下来I行,每行两个字母,表示I可以用这两个字母替代.接下来N行,每行两

BZOJ1054|HAOI2008移动玩具|广搜

Description在一个4*4的方框内摆放了若干个相同的玩具,某人想将这些玩具重新摆放成为他心中理想的状态,规定移动时只能将玩具向上下左右四个方向移动,并且移动的位置不能有玩具,请你用最少的移动次数将初始的玩具状态移动到某人心中的目标状态.Input前4行表示玩具的初始状态,每行4个数字1或0,1表示方格中放置了玩具,0表示没有放置玩具.接着是一个空行.接下来4行表示玩具的目标状态,每行4个数字1或0,意义同上.Output一个整数,所需要的最少移动次数.Sample Input111100

【BZOJ】1054: [HAOI2008]移动玩具(bfs+hash)

http://www.lydsy.com/JudgeOnline/problem.php?id=1054 一开始我还以为要双向广搜....但是很水的数据,不需要了. 直接bfs+hash判重即可. #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> using n

BZOJ 1054 [HAOI2008]移动玩具

直接暴力广搜即可.. [网上有大神说双向广搜速度快,然而直接暴力广搜就可以过了] 队列中的状态用二进制来存储.. 我用了一个比较sb的写法,勿喷qaq 1 #include <queue> 2 #include <cstdio> 3 4 using namespace std; 5 6 unsigned int Start, End; 7 bool M[4][4]; 8 9 const int dx[] = {+0, +0, +1, -1}; 10 const int dy[] =

【BFS】bzoj1054 [HAOI2008]移动玩具

暴搜吧,可以哈希一下,但是懒得写哈希了,所以慢得要死. Code: 1 #include<cstdio> 2 #include<queue> 3 #include<set> 4 #include<algorithm> 5 using namespace std; 6 const int di[]={0,0,-1,1},dj[]={-1,1,0,0}; 7 struct Squ{char S[4][4];}; 8 struct Node{Squ v;int d

【[HAOI2008]移动玩具】

并不知道省选考这种爆搜题有什么意义.. 正文部分: 观察题目中只有12个数,每个数只有0和1,明显所以状态的数量为\(2^{12}=4096\),那岂不是爆搜随便做? 对于1个状态hash: 我们将现在这12位数打包成一个字符串,用\(map\)记录一下这个字符串是否出现过. 对于1个状态的unhash,我们将这个字符串转到1个矩阵里,就是当前的状态. 于是我们就可以轻松的得到每种情况的状态. 对于Bfs过程,我们对unhash完的矩阵进行操作,每次选取其中为1的点,分4个方向向外扩散,然后压成