今天测试了几个题,可以说是模版题
t1
工作依赖
题目描述
题目描述(Description):
2008年,奥运会将在中国举行。众所周知举办奥运会是一个庞大的工程,有许多准备工作要做,而这些工作也是要分先后、存在依赖关系的。比如我们说工作2依赖于工作1,意思是说在工作2开始做之前要必须结束工作1。我们假设,在一个时刻只有一个工作在进行,而且每样工作所依赖的其它工作不会超过10个。
输入文件(job.in):
第一行有两个整数N(0<=N<=10000)和M。所有工作从1到N编号。你需要计算第M个工作的最早结束时间。
接下来N行每行描述一个工作,第1行描述工作1,第二行描述工作2,……,以此类推。每行包含几个正整数,第i行的第1个整数是完成第i个工作需要的时间T(0<T<=100),第i行的其余数字是第i个工作所依赖的其它工作编号。我们保证不会出现循环依赖。
输出文件(job.out):
一个整数:工作M的最早结束时间。
样例(Sample):
Sample Input Case 1:
2 2
3
2 1
Sample Output Case 1:
5
Sample Input Case 2:
3 3
3
2 1
4 1 2
Sample Output Case 2:
9
这道题感觉是深搜,然而老师说是dp,不过好像差不多,我用深搜做的,注意存边时反向存,然后从m开始倒着跑
#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
英雄
题目描述
题目描述(Description):
城堡迷宫由N×M个格子组成,英雄Mario玛丽奥要在城堡迷宫中从起始点移动到目标点去拯救被怪物掳去的公主,他每一步只能从当前所在的格子移动到相邻的4个格子之一,而且不能移出城堡的范围,走一步需要1秒的时间。
城堡中某些格子里面有弹簧,每个弹簧具有特定的能量K,不同弹簧的K值不一定相同。如果Mario跳到一个有弹簧的格子,他就会继续向前跳K个格子或者被墙所阻挡无法继续向前,这个时间忽略不计。
10 |
|
|
|
|
|
|
|
|
|
|
◎:Mario ★:公主 ▲:弹簧 示例一:Mario现所在位置是(2,8),有一个弹簧在(2,7),能量值为5,则Mario只需向左走一步,就会被弹到(2,2),从(2,8)到(2,2)Mario只需一步,即1秒。 示例二:Mario现所在位置是(2,8),有一个弹簧在(2,7),能量值为10,则Mario只需向左走一步,就会被弹到(2,1),从(2,8)到(2,1)Mario只需一步,即1秒。 |
9 |
|
|
|
|
|
|
|
|
|
|
|
8 |
|
|
|
|
|
|
|
|
|
|
|
7 |
|
|
|
|
|
|
|
★ |
|
|
|
6 |
|
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
|
|
4 |
|
|
|
|
|
|
|
|
|
|
|
3 |
|
|
|
|
|
|
|
|
|
|
|
2 |
|
|
|
|
|
|
▲ |
◎ |
|
|
|
1 |
|
|
|
|
|
|
|
|
|
|
|
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
|
请你计算Mario从起始点到达目标点(公主位置)需要的最短时间,如果不能到达,输出“Impossible”。
输入文件(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”。(引号不需输出)
一个裸的深搜题,不过好像广搜快点,但加点优化剪枝也能过
#include<bits/stdc++.h> #define maxn 110 #define inf 0x3f3f3f3f using namespace std; int m,n,k,mp[maxn][maxn],ans=inf,bj[maxn][maxn],qdx,qdy,zdx,zdy; void dfs(int x,int y,int cost){ if(cost>ans) return; if(x==zdx&y==zdy) {ans=cost;return;} bj[x][y]=cost;//剪枝用 if(x+1<=n) {//shang int i=x+1,j=y; while(mp[i][j]){ i=min(n,i+mp[i][j]); } if(cost+1<bj[i][j]) dfs(i,j,cost+1); } if(x-1>=1){//xia int i=x-1,j=y; while(mp[i][j]){ i=max(1,i-mp[i][j]); } if(cost+1<bj[i][j]) dfs(i,j,cost+1); } if(y-1>=1){//zuo int i=x,j=y-1; while(mp[i][j]){ j=max(1,j-mp[i][j]); } if(cost+1<bj[i][j]) dfs(i,j,cost+1); } if(y+1<=m){//you int i=x,j=y+1; while(mp[i][j]){ j=min(m,j+mp[i][j]); } if(cost+1<bj[i][j]) dfs(i,j,cost+1); } return; } int main(){ memset(bj,inf,sizeof(bj)); scanf("%d%d",&n,&m); scanf("%d",&k); for(int i=1;i<=k;i++){ int x,y,z; scanf("%d%d%d",&x,&y,&z); mp[x][y]=z; } scanf("%d%d",&qdx,&qdy); scanf("%d%d",&zdx,&zdy); dfs(qdx,qdy,0); if(ans==inf) printf("Impossible\n"); else printf("%d\n",ans); return 0; }
t3
不老的传说
题目描述
题目描述(Description):
一位先知告诉Ddynamic,在遥远的地方,有一处不老的泉水,在那里,他可以找到他人生的意义。按照先知的指引,Dynamic出发了。翻越雪山,穿过丛林,度过汪洋,终于来到了沙漠的深处。按照先知的说法,泉水就在这个地方。然而除了无尽的沙漠之外,什么都没有。
Dynamic几乎绝望了,他盲目地走着,突然来到了一圈奇异的巨石前,在巨石阵的中央清晰地传来泉水轻快的声音。巨大的石头挡住了去路,Dynamic无法前进了。突然间,本来无色的石头闪烁出绚丽夺目的光芒,与泉水声交织成诗一般的乐章。然后一刹那间,色彩消失了。
“这里面一定又什么秘密,我要把石头染成刚才的颜色!”Dynamic对自己说,他还清楚地记得每一块石头的颜色。智慧女神雅典娜这时出现了,递给他一把神奇的刷子,说“这把刷子每次可以把连续的不超过K块石头刷成一种新颜色,新刷的颜色会覆盖原来的颜色。用最少的次数,恢复石阵的光彩,你就会找到不老的泉水。”
Dynamic意识到这并不是一件容易的事,他出发得太匆忙,忘了带上手提电脑。你能帮助他吗?
输入文件(dist.in):
第1行包含3个整数N,C,K。其中N是石头的个数,C是颜色的种类,K是每次最多刷过的石头的个数。1≤N≤200,1≤C,K≤N 。
第2行包含N个整数,分别是N块石头最终的颜色,按照顺时针的顺序。颜色是1到C之间的一个整数,整数之间用一个空格隔开。开始的时候,所有的石头都是无色的。
输出文件(dist.out):
输出一个整数,为需要的最少次数。
样例(Sample):
Sample Input Case 1:
5 2 3
1 2 1 2 1
Sample Output Case 1:
3
一个区间dp题,dp[i][j]表示从i到j的最优解,因为存在环,所以要化环为链,转移方程:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]) 如果s[i]==s[j] 那么当前状态可以从原来状态直接将其染色,即dp[i][j]=min(dp[i+1][j],dp[i][j-1])
#include<bits/stdc++.h> using namespace std; int n,m,t,a[401],s[401][401]; int main() { scanf("%d%d%d",&n,&m,&t); for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i+n]=a[i]; memset(s,0x3f3f3f3f,sizeof(s)); for(int i=1;i<=2*n;i++) s[i][i]=1; for(int i=1;i<n;i++) for(int l=1,r=i+1;r<=2*n;l++,r++) { if(i+1<=t&&a[l]==a[r]) s[l][r]=min(s[l+1][r],s[l][r-1]); for(int k=l;k<r;k++) s[l][r]=min(s[l][r],s[l][k]+s[k+1][r]); } int ans=0x3f3f3f3f; for(int i=1;i<n;i++) ans=min(ans,s[i][i+n-1]); printf("%d",ans); }