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;
}
(完)