MZOJ Contest 1074 搜索动规 经典题目 暴零 赛
T1:MZOJ1344 工作依赖
T2:MZOJ1345: 英雄
T3:MZOJ1346: 不老的传说
T1:MZOJ1344 工作依赖
DFS&&BFS
题目描述(Description):
2008年,奥运会将在中国举行。众所周知举办奥运会是一个庞大的工程,有许多准备工作要做,而这些工作也是要分先后、存在依赖关系的。比如我们说工作2依赖于工作1,意思是说在工作2开始做之前要必须结束工作1。我们假设,在一个时刻只有一个工作在进行,而且每样工作所依赖的其它工作不会超过10个。
输入文件(job.i n):
第一行有两个整数N(0<=N<=10000)和M。所有工作从1到N编号。你需要计算第M个工作的最早结束时间。
接下来N行每行描述一个工作,第1行描述工作1,第二行描述工作2,……,以此类推。每行包含几个正整数,第i行的第1个整数是完成第i个工作需要的时间T(0<T<=100),第i行的其余数字是第i个工作所依赖的其它工作编号。我们保证不会出现循环依赖。
输出文件(job.out):
一个整数:工作M的最早结束时间。
一道
毒瘤题
work模块还好打,但是readdata模块是真的难打readdata?readdata坑就坑在最后结尾没有’\n’这…既然没有\n那我们就避开\n这条道路。gets可以吗?可以但不好打还要特判\n和空格前面的数字。scanf%s可以吗?不行!scanf%c可以吗?很难。那怎么办?去看看数据特点。
在每一个数据前面都有一个空格(除第一个外)那么我们就可以用getchar或者scanf%c去读空格,剩下的就用scanf%d就ok算法?有题意,BFS/DFS都行。但需注意两点。建变的时候需要建
反向边
为啥?如果正向边不管是DFS/BFS都无法保证当前借点的fa都做过(建议画图试试)
用BFS遍历的时候最好从m开始。
T1:BFS
#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+10;
struct EDGE
{
int u,v,nxt;
}edge[1000005];
int d[maxn],out[maxn],head[maxn],size=0,used[maxn];
int ans=0;
int n,m;
queue<int>q;
void add(int u,int v)
{
edge[size].u=u;
edge[size].v=v;
edge[size].nxt=head[u];
head[u]=size++;
}
void init()
{
freopen("A.in","r",stdin);
}
void readdata()
{
char c[100];
int a;
memset(head,-1,sizeof(head));
scanf("%d%d\n",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i]);
while(getchar()==' ')
{
scanf("%d",&a);
add(i,a);
}
}
}
void BFS()
{
q.push(m);used[m]=1;ans+=d[m];
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];~i;i=edge[i].nxt)
{
int v=edge[i].v;
if(!used[v])
{
ans+=d[v];
used[v]=1;
q.push(v);
}
}
}
printf("%d\n",ans);
}
int main()
{
// init();
readdata();
BFS();
return 0;
}
T1:DFS
#include<bits/stdc++.h>
#define maxn 10010
#define maxm 100010
using namespace std;
int n,m,cost[maxn],size=0,head[maxn],bj[maxn];
struct edge{
int v,nex;
}e[maxm];
void adde(int u,int v){e[size].v=v;e[size].nex=head[u];head[u]=size++;}
int dfs(int u){
int ans=cost[u];
bj[u]=1;
for(int i=head[u];~i;i=e[i].nex){
int v=e[i].v;if(bj[v]) continue;
ans+=dfs(v);
}
return ans;
}
int main(){
memset(head,-1,sizeof(head));
memset(bj,0,sizeof(bj));
scanf("%d",&n);scanf("%d",&m);
for(int i=1;i<=n;i++){
scanf("%d",cost+i);
while(getchar()==' ') {
int u;
scanf("%d",&u);
adde(i,u);
}
}
printf("%d",dfs(m));
return 0;
}
T2:MZOJ1345: 英雄
BFS DFS剪枝不够好的话要超时
题目描述(Description):
城堡迷宫由N×M个格子组成,英雄Mario玛丽奥要在城堡迷宫中从起始点移动到目标点去拯救被怪物掳去的公主,他每一步只能从当前所在的格子移动到相邻的4个格子之一,而且不能移出城堡的范围,走一步需要1秒的时间。
城堡中某些格子里面有弹簧,每个弹簧具有特定的能量K,不同弹簧的K值不一定相同。如果Mario跳到一个有弹簧的格子,他就会继续向前跳K个格子或者被墙所阻挡无法继续向前,这个时间忽略不计
输入文件(hero.in):
第一行,两个整数,N和M(3<=N,M<=100),分别表示城堡的行和列。
第二行,一个非负整数K,表示弹簧的数量。接下来K行,每行含3个正整数——X,Y,P。其中X,Y是弹簧的坐标(2<=X<=N-1,2<=Y<=M-1),P是该弹簧的能量。
接下来最后两行,第一行是Mario的坐标,第二行是公主的坐标。
注意:输入文件保证没有一个弹簧是挨着城堡围墙的。
输出文件(hero.out):
输出Mario从初始位置到达公主所在位置需要的最短时间(秒)。
如果不能到达,则输出“Impossible”。(引号不需输出)
这道题比较坑的就是有弹簧!而且可以跳来跳去的那种!
贴上50分TLE代码DFS
#include <bits/stdc++.h>
using namespace std;
const int maxn=102;
int n,m,k;
int ans=0x7f7f7f;
int beginx,beginy,endx,endy;
int dx[]={0,0,-1,1,0};
int dy[]={0,-1,0,0,1};
int mapp[maxn][maxn],used[maxn][maxn];
void init()
{
freopen("B.in","r",stdin);
}
void readdata()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=k;i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
mapp[x][y]=z;
}
scanf("%d%d%d%d",&beginx,&beginy,&endx,&endy);
}
void dfs(int x,int y,int sum)
{
if(x==endx && y==endy)
{
ans=min(ans,sum);
return;
}
if(sum>ans)return;
if(x<=0 || y<=0)return;
if(x>n || y>m)return;
for(int i=1;i<=4;i++)
{
int nx=x+dx[i],ny=y+dy[i];
if(!used[nx][ny])
{
used[nx][ny]=1;
if(mapp[nx][ny])
{
int number=mapp[nx][ny];
int nnx=nx+dx[i]*number;
int nny=ny+dy[i]*number;
if(nnx<=0)nnx=1;if(nnx>n)nnx=n;
if(nny<=0)nny=1;if(nny>m)nny=m;
if(!used[nnx][nny])dfs(nnx,nny,sum+1);
}
dfs(nx,ny,sum+1);
used[nx][ny]=0;
}
}
}
void work()
{
used[beginx][beginy]=1;
dfs(beginx,beginy,0);
if(ans!=0x7f7f7f)printf("%d",ans);
else printf("Impossible");
}
int main()
{
init();
readdata();
work();
return 0;
}