Ecust2019算法练习4-BFS

Ecust2019算法练习4-BFS

题目如下,选自hdu

如何查找原题,每题我都给出了对应hdu的题号,只需搜索:
http://acm.hdu.edu.cn/showproblem.php?pid=此处要更改成对应题号(如1560)
在这里插入图片描述
省略以下图片*10
在这里插入图片描述

下面开始附上题解,代码在最后,第一次做这种活,欢迎批评指正。

1001
  • 01 Ignatius and the Princess I hdu1026

  • 题意:王子(0,0)救公主(n-1,m-1)(2<n,m<100)。.为空地,数字为延时怪物,要停留num秒,X为陷阱。求最短用时。如果无法到达,则输出特定语句。

  • 输入:n,m随后跟着n,m个迷宫。输出,最短用时/特定语句。

  • 题解:BFS+优先队列+回溯。与DFS不同的是,BFS是通过构建node结构体{记录(x,y),step值}。首先第一个node入队,当队列非空,优先级队列队首top(非front)出队,不越界就访问。然后遍历4个方向。空地step+1,非空地step+hp+1。If(step)非0,开始回溯输出。

  • 技巧: 回溯法,由于本题输出复杂,因此写成迭代版本用way[i]存储,way开错了大小导致我交了3发WA。将cx,cy赋值给N,M。然后way[i].(x,y)=(cx,cy),如果是怪兽,要一直根据hp倒推。最后根据dic[x][y]赋值新cx,cy.

  • 复杂度:O(nm)

1002
  • 02 Bitset

  • 题意:把一个数转换为二进制。

  • 输入:n个数;输出n个数的二进制

  • 题解:递归,不断对2取余即可。

  • 技巧: 模拟题。

  • 复杂度:O(logN)

1003
  • I NEED A OFFER! hdu1203

  • 题意:用n(<=10000)万申请m(<=10000)个学校,每个学校要a(<n)万且成功概率时b(实型)。问至少申请成功一个的概率。

  • 输入:n,m,随后跟m个学校的ai,bi;输出:概率XX.X%。

  • 模板:动态规划的背包模型。目标:这题的目标是最大概率值。可以由此得到结果1-(1-pi)(1-qi)。因此不是要简单记录背包的概率和。那么状态转移方程为dp[v]=max(dp[v], 1-(1-dp[v-v[i]])*(1-a[i]));

  • 技巧:WA了一次,dp[]和p[]数组要double类型。

  • 复杂度:O(mV)

1004
  • 非常可乐 hdu1495

  • 题意:给定三个没有刻度只能倾倒的杯子,容量分别为S,N,M(S=N+M,0<S<101)分可乐。要求容量为S的可乐经过最少次倾倒步骤平分为S/2。问能平分的话最少次数。

  • 输入:S,N,M;输出:次数或Yes/No

  • 题解:BFS。三个杯子倒可能有6种状态,S->N,S->M,M->S,M->N,N->S,N->M。因此解空间为从(S,0,0)出发的三叉子集树。其中,在S=S/2,若N大于M,N=S/2时到达叶结点,因为是层序遍历,最先到达叶结点的即为最短的。要搜索的状态不需要再次搜索,所以要开vis数组记录搜索状态,防止走回头路。

  • 技巧: 这题也可以模拟做,但我交了一发WA,原因是16 10 6这组数据为7.网上的题解可以用数论知识的最大公因数做。以后可以尝试找找规律

  • 复杂度:O(SNM)

1005
  • 05 A计划 hdu2102

  • 题意:两层迷宫。给定步数,问能否到终点。迷宫特点,#传送到另一层,无需任何时间。

  • 输入:T,n,m,t随后跟着n*m的迷宫;输出YES/NO

  • 题解:BFS,解空间为完全四叉树。叶结点为有路径到达终点且满足t<=14。迷宫最短路问题,准备好结构体,图数组,vis数组,增量数组。越界Out函数。叶结点bool变量ok。

  • 技巧: 交了6发WA。Yes写错,getchar()没加去空格,叶结点不对,ok没初始化,没考虑#死循环,空地没算P。

  • 复杂度:O(nm)

1006
  • 06 胜利大逃亡

  • 题意:二维迷宫变三维了。问最短路径

  • 输入:T,a,b,c,t随后跟着三维迷宫;输出:最短步数或-1

  • 题解:BFS,解空间为完全六叉树。加个z维度就好了。

  • 技巧: 交了一发WA。题意是超出规定时间也是-1。这题1600ms,限制是2000ms。比较水。写个白板算法可以通过。

  • 复杂度:O(abc)

1007
  • 07 Max Clique

  • 题意:最大团问题。给定一个无向图G,找一个子图是完全图,求子图的最大顶点数目。

  • 输入:顶点数目n(1<n<50),随后跟着n行n列记录矩阵临界情况。输出:最大数目

  • 题解:DFS,解空间为取与不取顶点的完全二叉子集树。叶结点为达到了顶点数目n,更新最大数目。取的条件是与前几个顶点都连通,不取的条件是已然达不到最好的情况。故DFS(int t,int v)表示第t步的最大团为v。

  • 技巧: 这题卡常,需要小小的优化一下,可行性剪枝和最优化剪枝都要做。判断能否取时不必判断所有点,判断当前层之前的点即可。然后这题也不用开vis[]数组记录过访问的顶点。因为子集树一定要有x[]记录当前结点取不取,即可代替vis[]数组功能。

  • 复杂度:O(2^n)

1008
  • 08 Going Home hdu1533 http://acm.hdu.edu.cn/showproblem.php?pid=1533

  • 题意:给定地图可算出人和房子的曼哈顿距离。问n(n<100)个人进n个房子的最短距离。

  • 输入:n,m随后跟着n*m的地图;输出最短距离

  • 题解:BFS+MCMF.最小费用最大流问题模型。给定网络N=(V,E,c,w,s,t),每一弧(vi,vj)属于E上,除了已给容量cij外,还给了一个单位流量的费用w(vi,vj)≥O(简记为wij)。所谓最小费用最大流问题就是要求一个最大流f,使得流的总输送费用取最小值W(f)=Σwij*fij。

  • 技巧: 第一次做这种题目。需要在B站补个视频应该才能看明白。

  • 复杂度:O(n^5)

1009
  • 09 DNA sequence hdu1560 http://acm.hdu.edu.cn/showproblem.php?pid=1560

  • 题意:给定n(1<n<8)个ATGC的DNA小串(串长<5),找一个大串让每个子串为其子序列。求大串的最短长度。

  • 输入:n,随后跟着n个串;输出:串的最短长度。

  • 题解:DFS加回溯。解空间为完全四叉树,根据取ATGC四种状态搜索。叶结点在当前大串的最短长度re下,n个子串所有字符都被用光,或进行最优化判断不可能的剪枝(用remain()实现最优化剪枝函数max(a[k]-pos[k])),在这里维护pos[k]为第K个串在使用自己的第几个位置。如果大串选的ATGC中的一个,可以成为子串的一位,继续向下搜索更新step与pos[k]++,直至达到叶结点或被剪掉。主函数中,当预计长度+当前长度<最优长度re时,这时跳出dfs,但仍在主函数的while(true)循环中,令re++,再次dfs,直到找到第一次符合要求的re,此时即为最短,跳出循环。

  • 技巧: 这题搜索比较难,属于搜索进阶-迭代加深搜索。具体来说就是,首先深度优先搜索k层,若没有找到可行解,再深度优先搜索k+1层,直到找到可行解为止。由于深度是从小到大逐渐增大的,所以当搜索到结果时可以保证搜索深度是最小的。这也是迭代加深搜索在一部分情况下可以代替广度优先搜索的原(还比广搜省空间)。当有一类问题需要做广度优先搜索,但却没有足够的空间,而时间却很充裕,碰到这类问题,我们可以选择迭代加深搜索算法。剪枝操作:使用迭代加深搜素时没有剪枝操作时,时间开销是非常大的(因为迭代加深搜索是通过限制每次dfs的最大深度进行的搜索。令maxd表示最大的搜索深度,那么dfs就只能在0~maxd之间来进行,如果在这个范围内找到了解,就退出大循环,否则maxd++,扩大搜索范围。所以可想而知,倘若没有高效及时的退出无解的情况,那么时间上的开销也是会比较大的。)如何及时的退出无解情况呢?这里引入乐观估计函数。而对于本题的乐观估计函数为(if(remain()+step > re) return 0;)而remain()的实现为,串k长-串当前用了pos[k]长的max,就是剩余长度。参考自CSDN,原文链接:https://blog.csdn.net/hzaukotete/article/details/81226556

  • 复杂度:O(len(s)^n)

1010
  • 10 推箱子 hdu1254

  • 题意:地图为M*N,有空地,墙,箱子和终点。问人将箱子推到终点的最少步数。

  • 输入:m,n随后跟着M*N维度的地图;输出最少步数或-1

  • 题解:BFS。当前状态用搬运工和箱子坐标四元组表示。如果人和箱子重合,视为推动了一次箱子。那么人走的状态分为空地,箱子。越界剪枝,访问过剪枝。当人走到箱子时,剪枝箱子撞墙出界。访问过的状态一定要以4元组记录,若以两元组记录可能出现因推箱子绕路导致的此路因访问过走不了,造成WA。因此BFS也要存4个状态。

  • 技巧: 这题交了一发WA就是上述原因。让我惊讶的是,第二发就过了,优先级队列的代码竟然0msAC!!!!!用优先级队列是因为要输出最少步数,所以按结点的最少步骤出队遍历。非优先级队列代码要繁琐一些,有可能不能0msAC。

  • 复杂度:O(M*N)

代码合集,仅供参考!!!

//1001
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int n, m, step;
const int maxn = 110;
char G[maxn][maxn];
bool vis[maxn][maxn];
int dic[maxn][maxn]; //回溯用
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0}; //右下左上
string s = " seconds to reach the target position, let me show you the way.";
struct NODE
{
    int x;
    int y;
    int step;
    friend bool operator<(NODE n1, NODE n2)
    {
        return n1.step > n2.step; //默认大根堆,要反着写
    }
} node, cur, nextt, way[10001];
bool out(int x, int y)
{
    if (x < 1 || y < 1 || x > n || y > m)
        return 1;
    if (vis[x][y])
        return 1;
    if (G[x][y] == 'X')
        return 1;
    return 0;
}
int bfs(int x, int y)
{
    priority_queue<NODE> q; //优先级队列,小根堆
    cur.x = x;
    cur.y = y;
    cur.step = 0;
    q.push(cur);
    while (!q.empty())
    {
        cur = q.top();
        q.pop();
        int cx = cur.x, cy = cur.y, cstep = cur.step;
        //完成
        if (cx == n && cy == m)
            return cstep;
        for (int i = 0; i < 4; i++)
        {
            int xx = cx + dx[i];
            int yy = cy + dy[i];
            if (out(xx, yy))
                continue;
            vis[xx][yy] = 1;
            dic[xx][yy] = i;
            if (G[xx][yy] == '.')
            {
                nextt.x = xx;
                nextt.y = yy;
                nextt.step = cstep + 1;
            }
            else
            { //怪兽
                int hp = G[xx][yy] - '0';
                nextt.x = xx;
                nextt.y = yy;
                nextt.step = cstep + 1 + hp;
            }
            q.push(nextt);
        }
    }
    return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
    while (cin >> n >> m)
    {
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= m; j++)
            {
                cin >> G[i][j];
            }
        }
        memset(vis, 0, sizeof(vis));
        vis[1][1] = 1;
        step = bfs(1, 1); //遍历得到step
        if (step)
        {
            int cx = n, cy = m;
            for (int i = step; i > 0; i--)
            {
                way[i].x = cx;
                way[i].y = cy;
                if (G[cx][cy] >= '1' && G[cx][cy] <= '9')
                {
                    int hp = G[cx][cy] - '0';
                    for (int j = 1; j <= hp; j++)
                    {
                        way[i - j].x = cx;
                        way[i - j].y = cy;
                    }
                    i = i - hp;
                }
                switch (dic[cx][cy])
                {
                case 0:
                    cy--;
                    break;
                case 1:
                    cx--;
                    break;
                case 2:
                    cy++;
                    break;
                case 3:
                    cx++;
                    break;
                }
            }
            cout << "It takes " << step << s << endl;
            cout << "1s:(0,0)->(" << way[1].x - 1 << "," << way[1].y - 1 << ")" << endl;
            for (int i = 2; i <= step; i++)
            {
                if (way[i].x == way[i - 1].x && way[i].y == way[i - 1].y)
                    cout << i << "s:FIGHT AT (" << way[i].x - 1 << "," << way[i].y - 1 << ")" << endl;
                else
                    cout << i << "s:(" << way[i - 1].x - 1 << "," << way[i - 1].y - 1 << ")->(" << way[i].x - 1 << "," << way[i].y - 1 << ")" << endl;
            }
        }
        else
            cout << "God please help our poor hero." << endl;
        cout << "FINISH" << endl;
    }
    return 0;
}
//1002
#include <bits/stdc++.h>
using namespace std;
const int maxn = 10010;
int a[maxn];
int main(){
    //freopen("in.txt","r",stdin);
    int n,t;
    while(cin>>n){
        int id = 0;
        memset(a,0,sizeof(a));
        t = n;
        while(t){
            a[id++] = t%2;
            t /= 2;
        }
        for(int i = id-1; i >= 0; i--){
            cout<<a[i];
        }
        cout<<endl;
    }
    return 0;
}
//1003
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 10010;
double dp[maxn],p[maxn];//WA,类型注意
int a[maxn];
int main(){
    freopen("in.txt","r",stdin);
    int n,m,i,j;
    while(scanf("%d%d",&n,&m)!=EOF){
      if(m==0&&n==0) break;
      for(i=0;i<m;i++){
          scanf("%d%lf",&a[i],&p[i]);
  //不能得到Offer的概率
      }
      //为滚动数组初始化为1
      for(i=0;i<=n;i++) dp[i]=0;  
      for(i=0;i<m;i++) //m个物品
        for(j=n;j>=a[i];j--)
              dp[j]=max(dp[j],1-(1-dp[j-a[i]])*(1-p[i]));//求最小的不能得到的dp[n]
          printf("%.1lf%%\n",dp[n]*100);
        
    }
    return 0;
}
//1004(感谢大佬代码)
// 假设都考虑可以到的话 是不是就是有6中状态可以转移
//比如a->b 表示的就是a往b里面倒   s水杯不变  所以就可以有
//  a->b  b->a  a->s   s->a  s->b   b->s   现在只要考虑的是考虑一个情况就行
//  以下的代码就考虑一个情况  其他的去类推
#include <bits/stdc++.h>
#define ll long long
const int maxn=105;
using namespace std;
int s,a,b;
struct node
{ 
 int a,b,s,cnt;   //a,b,s 表示的是水杯  cnt表示次数,a大b小
}st;                 //st  记录的起始的状态  
queue<node>q;     //这题需要用到队列  可以自己理解下先进先出
int vis[maxn][maxn];    //vis[a][b]记录的是当前的状态是不是已经有了,也就是之前有没有到达这个状态;
int bfs()
{
 memset(vis,0,sizeof(vis));   //每次需要初始话 
 while(!q.empty())  q.pop();   //清空队列
 st.a=0,st.b=0,st.s=s,st.cnt=0;    //st赋初值
 q.push(st);       //将这个放入队列中
 vis[a][b]=1;       //表示的这个状态已经倒过了
 while(!q.empty()){           //q.empty()表示的是队列有元素
   node hh=q.front();   //hh表示的是当前的状态
   node pp;                  //  pp表示的是接下来可以转换的状态
   if(hh.a==s/2&&hh.s==s/2)     //这里判断的就是能过分成两份相等的,之前已经将a划分成比b大的水杯了 
    return hh.cnt;
   if(hh.s&&hh.a!=a)     //这里就拿一个过程来说   s->a  表示的就是s倒进a水杯  
   {                                //if判断的就hh.s必须有水和hh.a中水不能是满水  自己去理解下if判断条件
    int c=a-hh.a;             //这里表示的就是a水杯还能过倒多少水
    if(hh.s>=c) pp.a=a,pp.s=hh.s-c;      //如果当前的hh记录的hh.s水够倒入a的话,那么就是a水杯水就满了,也就是pp.a=a;  那么s水杯剩下的就是原来hh.s-c;
    else   pp.a=hh.a+hh.s,  pp.s=0;        //如果s水杯的水不够a水杯中的  比如s中有4升   而a水杯需要加入5的话 ,就是这样的,那么s水杯肯定是pp.s=0;表示倒完了
                                                                      //a水杯现在的水pp.a=原来的hh.a(原来的a杯水)+s中的水
    pp.b=hh.b;                                     //b水杯肯定没有参加这次的过程  ,所以新的状态pp.b==原来的状态
    pp.cnt=hh.cnt+1;                          //cnt记录的就是转移的步数   表示的是之前的步数加+1
    if(!vis[pp.a][pp.b])                   //这个是关键   vis[][]表示的就是一个状态的记录,表示的当前a,b水杯是不是在之前就倒过了 这个真的需要理解
    {
     q.push(pp);               //如果这个状态没有倒过  我们就需要将这个放入队列
     vis[pp.a][pp.b]=1;    //标记这个状态已经倒过了
    }
   }
   //剩下的五个过程一模一样
   if(hh.s&&hh.b!=b)
   {
    int c=b-hh.b;
    if(hh.s>=c) pp.b=b,pp.s=hh.s-c;
    else   pp.b=hh.b+hh.b,  pp.s=0;
    pp.a=hh.a;
    pp.cnt=hh.cnt+1;
    if(!vis[pp.a][pp.b])
    {
     q.push(pp);
     vis[pp.a][pp.b]=1;
    }
   }
   if(hh.a&&hh.s!=s)
   {
    int c=s-hh.s;
    if(hh.a>=c) pp.s=s,pp.a=hh.a-c;
    else   pp.s=hh.s+hh.a,  pp.a=0;
    pp.b=hh.b;
    pp.cnt=hh.cnt+1;
    if(!vis[pp.a][pp.b])
    {
     q.push(pp);
     vis[pp.a][pp.b]=1;
    }
   }
   if(hh.a&&hh.b!=b)    //a->b
   {
    int c=b-hh.b;
    if(hh.a>=c) pp.b=b,pp.a=hh.a-c;
    else   pp.b=hh.b+hh.a,  pp.a=0;
    pp.s=hh.s;
    pp.cnt=hh.cnt+1;
    if(!vis[pp.a][pp.b])
    {
     q.push(pp);
     vis[pp.a][pp.b]=1;
    }
   }
   if(hh.b&&hh.a!=a)
   {
    int c=a-hh.a;
    if(hh.b>=c) pp.a=a,pp.b=hh.b-c;
    else   pp.a=hh.a+hh.b,  pp.b=0;
    pp.s=hh.s;
    pp.cnt=hh.cnt+1;
    if(!vis[pp.a][pp.b])
    {
     q.push(pp);
     vis[pp.a][pp.b]=1;
    }
   }
   if(hh.b&&hh.s!=s)
   {
    int c=s-hh.s;
    if(hh.b>=c) pp.s=s,pp.b=hh.b-c;
    else   pp.s=hh.s+hh.b,  pp.b=0;
    pp.a=hh.a;
    pp.cnt=hh.cnt+1;
    if(!vis[pp.a][pp.b])
    {
     q.push(pp);
     vis[pp.a][pp.b]=1;
    }
   }
   q.pop();          //用完了这个记得出队列
 }
 return 0;
}
int main()
{
    //freopen("in.txt","r",stdin);
 while(cin>>s>>a>>b){
   if(s==0&&a==0&&b==0)
    break;
   if(s%2)         //如果是奇数的话,不可能
   {
    puts("NO");
    continue;
   }
   if(a<b)
    swap(a,b);   //这里将a b水杯转换  然后的话 更容易判断
   int ans=bfs();
   if(ans) printf("%d\n",ans);
   else     puts("NO");
 }
 return 0;
}
//1005

//1005
#include<bits/stdc++.h>
using namespace std;
int T,n,m,t;
struct node{
    int x,y,z,v;
    node() {}
    node(int _x,int _y,int _z,int _v):x(_x),y(_y),z(_z),v(_v) {}
}c;
int cx,cy,cz,cv,nx,ny,nz,nv;
char G[12][12][3];
bool vis[12][12][3];
int dx[] = {1,0,-1,0};//下,右,上,左
int dy[] = {0,1,0,-1};
inline bool out(int x,int y){
    if(x < 1 || x > n || y < 1 || y > m) return 1;
    else return 0;
}
bool ok;
void bfs(){
    queue<node> q;
    q.push(node(1,1,1,0));
    while(!q.empty()){
        c = q.front(); q.pop();
        cx = c.x;cy = c.y;cz = c.z;cv = c.v;
        //cout<<G[cx][cy][cz]<<cx<<cy<<cz<<" "<<cv<<endl;
        if(G[cx][cy][cz]=='P' && cv <= t){
            ok = 1;
            return;
        }
        for(int i = 0; i < 4; i++){
            nx = cx + dx[i];
            ny = cy + dy[i];
            if(out(nx,ny) || vis[nx][ny][cz]) continue;
            if(G[nx][ny][cz]=='*') continue;
            if(G[nx][ny][cz]=='#'&&G[nx][ny][3-cz]=='*') continue;
            if(G[nx][ny][cz]=='#'&&G[nx][ny][3-cz]=='#') continue; //没考虑死循环,WA++
            if(G[nx][ny][cz]=='.' || G[nx][ny][cz]=='P'){ //没考虑P,WA++
                nv = cv+1;
                vis[nx][ny][cz] = 1; 
                q.push(node(nx,ny,cz,nv));
            } 
            if(G[nx][ny][cz]=='#'){
                nz = 3-cz; nv = cv+1;
                vis[nx][ny][cz] = 1;
                vis[nx][ny][nz] = 1;  
                q.push(node(nx,ny,nz,nv));
            } 
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    cin>>T;
    while(T--){
        memset(vis,0,sizeof(vis));
        ok = 0;
        vis[1][1][1] = 1;
        cin>>n>>m>>t;
        getchar(); //吸\n
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%c", &G[i][j][1]);
            }
            getchar();//吸\n
        }
        getchar();//吸\n
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= m; j++){
                scanf("%c", &G[i][j][2]);
            }
            getchar();
        }
        bfs();
        if(ok) cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}
//1006
#include<bits/stdc++.h>
using namespace std;
#define MAX 0x3fffffff
int T,a,b,c,t;
struct node{
    int x,y,z,v;
    node() {}
    node(int _x,int _y,int _z,int _v):x(_x),y(_y),z(_z),v(_v) {}
}d;
int G[51][51][51];
bool vis[51][51][51];
int bestv;
int cx,cy,cz,cv,nx,ny,nz,nv;
int dx[]={0,0,1,-1,0,0};
int dy[]={1,-1,0,0,0,0};
int dz[]={0,0,0,0,1,-1};
bool out(int x, int y,int z){
    if(G[x][y][z] == 1) return 1;
    if(vis[x][y][z]) return 1;
    if(x<1 || x>b || y<1 || y>c || z<1 || z>a) return 1;
    return 0;
}
void bfs(){
    bestv = MAX;
    queue<node> q;
    q.push(node(1,1,1,0));
    while(!q.empty()){
        d = q.front(); q.pop();
        cx=d.x;cy=d.y;cz=d.z;cv=d.v;
        //cout<<cx<<cy<<cz<<cv<<endl;
        if(cx==b&&cy==c&&cz==a){
            bestv = min(bestv,cv);
        }
        for(int i = 0; i < 6; i++){
            nx=cx+dx[i];ny=cy+dy[i];nz=cz+dz[i];
            if(out(nx,ny,nz)) continue;
            nv=cv+1;
            vis[nx][ny][nz] = 1;
            q.push(node(nx,ny,nz,nv));
        }
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    cin>>T;
    while(T--){
        memset(vis,0,sizeof(vis));
        cin>>a>>b>>c>>t;
        for(int i = 1; i <= a; i++){
            for(int j = 1; j <= b; j++){
                for(int k = 1; k <= c; k++){
                    scanf("%d",&G[j][k][i]);
                }
            }
        }
        bfs();
        if(bestv == MAX || bestv>t) cout<<-1<<endl;
        else cout<<bestv<<endl;
    }
    return 0;
}
//1007
#include<bits/stdc++.h>
using namespace std;
bool G[51][51];
int bestv,n;
bool x[51];
void dfs(int t,int v){//第t步的最大团为v
    if(t == n+1){
        if(bestv<v) bestv = v;
        return;
    }
    bool ok = 1;
    for(int i = 1; i < t; i++){
        if(G[i][t] == 0 && x[i]){//选的边无联通
            ok = 0;
            break;
        }
    }
    if(ok){//可以选这个点
        x[t]=1;
        //cout<<t<<"l"<<v<<endl;
        dfs(t+1,v+1);
        x[t]=0;
    }
    //不选这个点v + (n - t) <= bestv
    if(v + n - t > bestv){
        x[t]=0;
        //cout<<t<<"r"<<v<<endl;
        dfs(t+1,v);
    }
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    while(cin>>n,n){
        bestv = 0;
        memset(x,0,sizeof(x));
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                scanf("%d",&G[i][j]);
            }
        }
        x[1]=0;
        dfs(1,0);
        cout<<bestv<<endl;
    }
    return 0;
}
//1008
#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=105*2;
int n,m,vis[maxn],d[maxn],p[maxn],a[maxn];//p[maxn]存储边的编号;
char f[105][105];
struct node{
    int x,y;
    int dist(node b)  //曼哈顿距离
    {
        return abs(x-b.x)+abs(y-b.y);
    }
}man[105],house[105];
struct Edge{
    int from,to,cap,flow,cost;
    Edge(int u,int v,int c,int f,int w){
        from=u,to=v;
        cap=c,flow=f,cost=w;
    }
};
vector<Edge>edges;
vector<int>G[maxn];
struct MCMF{
    int n,m;
    void init(int n){
        this->n=n;
        for(int i=0;i<n;i++) G[i].clear();
        edges.clear();
    }
    void addedge(int from,int to,int cap,int cost){
        edges.push_back(Edge(from,to,cap,0,cost));
        edges.push_back(Edge(to,from,0,0,-cost));
        m=edges.size();
        G[from].push_back(m-2);//正向边和反向边的编号相差1
        G[to].push_back(m-1);
    }
    bool bellmanford(int s,int t,int& flow,long long& cost){
        for(int i=0;i<n;i++) d[i]=INF;
        memset(vis,0,sizeof(vis));
        d[s]=0,vis[s]=1,p[s]=0,a[s]=INF;
        queue<int>Q;
        Q.push(s);
        while(!Q.empty()){
            int u=Q.front();
            Q.pop(),vis[u]=0;
            for(int i=0;i<G[u].size();i++){
                Edge& e=edges[G[u][i]];
                if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
                    d[e.to]=d[u]+e.cost;
                    p[e.to]=G[u][i];
                    a[e.to]=min(a[u],e.cap-e.flow);
                    if(!vis[e.to]){
                        Q.push(e.to);
                        vis[e.to]=1;
                    }
                }
            }
        }
        if(d[t]==INF) return false;
        flow+=a[t];
        cost+=(long long)d[t]*(long long)a[t];
        for(int u=t;u!=s;u=edges[p[u]].from){
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];//通过位运算得到反向边编号
        }
        return true;
    }
    int mincostflow(int s,int t,long long& cost){
        int flow=0;
        cost=0;
        while(bellmanford(s,t,flow,cost));
        return flow;
    }
}mc;
int main(){
    while(~scanf("%d%d",&n,&m)&&(n||m)){
        for(int i=1;i<=n;i++) scanf("%s",f[i]+1);
        int p=0,q=0;
        for(int i=1; i<=n; i++)
            for(int j=1; j<=m; j++)
                if(f[i][j]=='m'){
                    man[p].x=i;
                    man[p].y=j;
                    p++;
                }
                else if(f[i][j]=='H'){
                    house[q].x=i;
                    house[q].y=j;
                    q++;
                }
        mc.init(p+q+2);//p+q+2个顶点
        for(int i=0;i<p;i++)
            for(int j=0;j<q;j++)
            	mc.addedge(i,p+j,1,man[i].dist(house[j]));
        for(int i=0;i<p;i++) mc.addedge(p+q,i,1,0);//源点到所有人的边
        for(int i=p;i<p+q;i++) mc.addedge(i,p+q+1,1,0); //所有房子到汇点的边
        long long ans;
        mc.mincostflow(p+q,p+q+1,ans);
        printf("%lld\n",ans);
    }
}
//1009
#include<bits/stdc++.h>
using namespace std;
int pos[11];//pos[i]  第i个序列正在使用第几个位置
int T,n;
int re;//自己构造的DNA序列最小长度
char c[10] = "ACGT";
struct node{
    char ch[11];      //DNA的组成
    int len;     //DNA长度
}a[11]; //a[i]  第i个DNA序列
int init(){//预估长度
    int ans=0;
    for(int i=0;i<n;i++)//总长度-正在使用的位置=剩下还没用的位置 即预计长度
        ans=max(ans,a[i].len-pos[i]);
    return ans;
}
int dfs(int step){
    //预计长度+当前长度>构造DNA序列的最小长度
    if(step+init()>re) return 0;
    //预计长度为0,即已完成
    if(init()==0) return 1;
    int pre[11];//先将pos保存起来,一会回溯要用
    for(int i=0;i<4;i++){//遍历ACGT
        int f=0;
        for(int j=0;j<n;j++)//保存pos
            pre[j]=pos[j];
        for(int j=0;j<n;j++)//当前这位符合,则该串的位置往后移一位
        {
            if(a[j].ch[pos[j]]==c[i])
            {
                f=1;
                pos[j]++;
            }
        }
        if(f){
            if(dfs(step+1))//有符合的,则往下搜索
                return 1;
            for(int j=0;j<n;j++)//回溯
                pos[j]=pre[j];
        }
    }
    return 0;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    cin>>T;
    while(T--){
        re=0;//自己构造的DNA序列最小长度
        cin>>n;
        for(int i=0;i<n;i++){//存值
            cin>>a[i].ch;
            a[i].len=strlen(a[i].ch);
            re=max(re,a[i].len);
            pos[i]=0;
        }
        while(1){
            if(dfs(0)==1) break;
            re++;//迭代深搜
        }
        cout<<re<<endl;
    }
    return 0;
}
//1010: 用时0ms!!AC闪瞎我了,本以为一定TLE还要剪枝,真是惊喜
#include<bits/stdc++.h>
using namespace std;
const int maxn=8;
int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int m,n,G[maxn][maxn];
int ax,ay,bx,by;
struct node{
    int hx,hy,bx,by; //人和箱子的位置
    int v; //步数
    node() {}
    node(int _hx,int _hy,int _bx,int _by,int _v){
        hx=_hx;hy=_hy;bx=_bx;by=_by;v=_v;
    }
    friend bool operator<(node a,node b){//小根堆,相反
        return a.v>=b.v;
    }
}c;
bool vis[maxn][maxn][maxn][maxn];
bool out(int x,int y){
    if(x<1 || x>m || y<1 || y>n) return 1;
    if(G[x][y]==1) return 1;
    return 0;
}
int bfs(){
    priority_queue<node> q;
    q.push(node(bx,by,ax,ay,0));
    while(!q.empty()){
        c=q.top(); q.pop();
        if(G[c.bx][c.by] == 3){
            return c.v;
        }
        for(int i = 0; i < 4; i++){
            int hxx = c.hx + dx[i];
            int hyy = c.hy + dy[i];
            if(out(hxx,hyy)) continue;
            if(vis[hxx][hyy][c.bx][c.by]) continue; //WA1,提前vis进入到状态,导致挪位置不可行,所以要记录4个位置
            if(hxx==c.bx&&hyy==c.by){
                int bxx = hxx + dx[i];
                int byy = hyy + dy[i];
                if(out(bxx,byy)) continue;
                vis[hxx][hyy][bxx][byy]=1;
                //cout<<"tui"<<hxx<<","<<hyy<<","<<bxx<<","<<byy<<","<<c.v+1<<endl;
                q.push(node(hxx,hyy,bxx,byy,c.v+1));
            }
            else{
                vis[hxx][hyy][c.bx][c.by]=1;
                //cout<<"ono"<<hxx<<","<<hyy<<","<<c.bx<<","<<c.by<<","<<c.v+1<<endl;
                q.push(node(hxx,hyy,c.bx,c.by,c.v));
            }
        }
    }
    return -1;
}
int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
    int T;
    cin>>T;
    while(T--){
        cin>>m>>n;
        memset(vis,0,sizeof(vis));
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++){
                scanf("%d",&G[i][j]);
                if(G[i][j]==2)ax=i,ay=j;
                else if(G[i][j]==4)bx=i,by=j;
            }
            vis[bx][by][ax][ay] = 1;
        printf("%d\n",bfs());
    }
    return 0;
}

(完)

特别鸣谢:感谢李震以及各位大佬的代码,如有错误,请您包涵

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值