【DFS_双调旅行商_Tri树_dp】网络搜集: AStar2014资格赛_解题报告
2014-05-25 18:02
357 查看
A.Energy Conversion(HDU4823)
DFS深搜,和我的解法完全一样= =……
B.Disk Schedule(HDU4824) From:晓风残月xj @CSDN
Another From:czz5242199@CSDN
本次最难的一题,相当于一个有约束条件的旅行商问题,这个约束条件就是你只能一开始先一直往右到达最右边,然后再一直往左回到起点。
由于移动轨道的时间和读取时间是固定的(400*2*MaxTrack + n*10),所以你需要的就是找到最小的为了读取所有数据的轨道转动时间。
用dist[i, j]表示第i个轨道和第j个轨道之间的差,则dist[i, j] = Min( abs(a[i]-a[j]), 360-abs(a[i]-a[j]))
之后考虑如何用动态规划来进行状态的表示,用f[i, j](i<=j)表示我们从i走到最右边的n,然后再走回j,期间刚好把[i, n]之间的所有点刚好都走一次,可以看出f[0][0]即为要求的目标
状态转移分为三种情况:
当i = j是,首先需要从i走到k(k>i),然后再遍历,所以f[j, j] = Min(dist[j, k] + f[k, j]) i<k<=n
当i = j-1时类似,f[j-1, j] = Min(dist[j-1, k] + f[k, j])
当i < j-1时,i如果不先走到i+1,则i+1就无法被遍历到了,因为之后往左的过程最多走到j,而i+1<j,所以f[i, j] = dist[i, i+1]+f[i+1, j]
C.Xor Sum(HDU 4825) From:洛阳纸迷@CSDN
Another From:czz5242199@CSDN
给出N个数(N<=10W),然后给出M个数(M<=10W),对于每个数p在之前的N个数中找出q使得 p xor q最大
一步一步考虑即可,首先选择使得p在二进制表示下最高位(第31位)是1的那些数,如果没有再选择会使得最高位为0的数
之后再之后选择的数中选择能够使得第30位为1的数
.......
直到最后
数据结构就选择trie树即可
D.Labyrinth (HDU4826) From:czz5242199@CSDN
给一个矩阵,一开始你在左上角,每个格子都有一个数,你可以选择向右,向下,向上走,但不能走重复,问你走到右上角的时候积累的和最大是多少
不能向左走是一个重要的特点,让我们可以使用动态规划
用f[i, j]表示走到第i行j列的时候最多能积累的和
首先f[i,j] = f[i,j-1]+a[i,j] (从左边走过来)
之后由于还可以上下走,所以对当前列上下各用一次动态规划即可,最后答案是f[0, M-1]
DFS深搜,和我的解法完全一样= =……
include <stdio.h> #include <string.h> const int maxn = 10000; int dfs(long long n,long long m,long long v,long long k,int tim){ if(n<=m)return tim; if(m<v || (m-v)*k<=m)return -1; return dfs(n,(m-v)*k,v,k,tim+1); } int main(){ int L,T; long long n,m,v,k; //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); scanf("%d",&T); for(L=1;L<=T;L++){ scanf("%I64d%I64d%I64d%I64d",&n,&m,&v,&k); printf("%d\n",dfs(n,m,v,k,0)); } return 0; }这是我AC的代码:
#include<cmath> #include<cstdio> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; int solve(ll n,ll m,ll v,ll k,int cnt) { if(m>=n) return cnt; return (m-v)*k<=m?-1:solve(n,(m-v)*k,v,k,cnt+1) ; } int main() { int cs; scanf("%d",&cs); for(int i=1;i<=cs;i++) { long long n=0,m=0,v=0,k=0; int cnt=0; scanf("%lld%lld%lld%lld",&n,&m,&v,&k); printf("%d\n",solve(n,m,v,k,cnt)); } return 0; }
B.Disk Schedule(HDU4824) From:晓风残月xj @CSDN
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; const int INF=100*1000*800; const int MAXN=1000+10; struct point { int x,y; }; point vert[MAXN]; int res[MAXN][MAXN]; int dis(int i,int j) { int t=abs(vert[i].x-vert[j].x)*400; int x1,x2; if(vert[i].y<vert[j].y) { x1=vert[i].y; x2=vert[j].y; } else { x1=vert[j].y; x2=vert[i].y; } int l=x2-x1; int r=360-x2+x1; return (l<r?l:r)+t; } int min(int a,int b) { return a < b ? a : b; } int work(int n) { int i,j; int s,Min=INF; res[2][1]=dis(2,1); for(i=2;i<=n;i++) { for(j=1;j<i;j++) { res[i][j]=min(res[i][j],res[i-1][j]+dis(i-1,i)); res[i][i-1]=min(res[i][i-1],res[i-1][j]+dis(j,i)); } } for(i=1;i<n;i++) { s=dis(i,n); if(Min > res [i] + s) Min = res [i] + s; } return Min; } int main() { int i,j,n,cas; cin>>cas; while(cas--) { scanf("%d",&n); vert[1].x=0; vert[1].y=0; for(i=2;i<=n+1;i++) scanf("%d%d",&vert[i].x,&vert[i].y); for(i=1;i<=n+1;i++) for(j=1;j<=n+1;j++) res[i][j]=INF; printf("%d\n",work(n+1)+n*10); } return 0; }
Another From:czz5242199@CSDN
本次最难的一题,相当于一个有约束条件的旅行商问题,这个约束条件就是你只能一开始先一直往右到达最右边,然后再一直往左回到起点。
由于移动轨道的时间和读取时间是固定的(400*2*MaxTrack + n*10),所以你需要的就是找到最小的为了读取所有数据的轨道转动时间。
用dist[i, j]表示第i个轨道和第j个轨道之间的差,则dist[i, j] = Min( abs(a[i]-a[j]), 360-abs(a[i]-a[j]))
之后考虑如何用动态规划来进行状态的表示,用f[i, j](i<=j)表示我们从i走到最右边的n,然后再走回j,期间刚好把[i, n]之间的所有点刚好都走一次,可以看出f[0][0]即为要求的目标
状态转移分为三种情况:
当i = j是,首先需要从i走到k(k>i),然后再遍历,所以f[j, j] = Min(dist[j, k] + f[k, j]) i<k<=n
当i = j-1时类似,f[j-1, j] = Min(dist[j-1, k] + f[k, j])
当i < j-1时,i如果不先走到i+1,则i+1就无法被遍历到了,因为之后往左的过程最多走到j,而i+1<j,所以f[i, j] = dist[i, i+1]+f[i+1, j]
#include <iostream> #include <cmath> using namespace std; int n, maxl, t, a[1001], ans, f[1001][1001], dist[1001][1001]; int min(int a, int b) { return a<b?a:b; } int main() { cin >> t; while (t--) { cin >> n; a[0] = 0; for (int i=1; i<=n; i++) cin >> maxl >> a[i]; for (int i=0; i<=n; i++) for (int j=i; j<=n; j++) dist[i][j] = min(abs(a[i]-a[j]), 360-abs(a[i]-a[j])); f = 0; for (int i=n-1; i>=0; i--) f[i] = f[i+1] +dist[i][i+1]; for (int j=n-1; j>=0; j--) { f[j][j] = dist[j] + f[j] ; if (j>0) f[j-1][j] = dist[j-1] + f[j] ; for (int i=j+1; i<n; i++) { f[j][j] = min(f[j][j], dist[j][i]+f[j][i]); if (j>0) f[j-1][j] = min(f[j-1][j], dist[j-1][i]+f[j][i]); } for (int i=j-2; i>=0; i--) f[i][j] = dist[i][i+1]+f[i+1][j]; } cout << maxl*800+n*10+f[0][0] << endl; } return 0; }
C.Xor Sum(HDU 4825) From:洛阳纸迷@CSDN
#include <iostream> #include <cstdio> #include <cstdlib> #define LENGTH 32 #define MAXN 100000 using namespace std; typedef struct node{ node *next[2]; bool flag; }; node Head; node arr[LENGTH * MAXN]; int nodeCount; node *GetNewNode(){ if (nodeCount >= LENGTH * MAXN) { printf("ERROR : node count full!"); exit(1); } arr[nodeCount].next[0] = NULL; arr[nodeCount].next[1] = NULL; arr[nodeCount].flag = false; return &(arr[nodeCount++]); } void Init(){ nodeCount = 0; Head.next[0] = NULL; Head.next[1] = NULL; Head.flag = false; } void insertNode(unsigned int num){ node *p = &Head; int temp; for (int i = LENGTH - 1; i>=0; i--){ if (((1<<i)&num) != 0){ temp = 1; } else { temp = 0; } if (p->next[temp] == NULL){ p->next[temp] = GetNewNode(); } p = p->next[temp]; } p->flag = true; } unsigned int searchNode(unsigned int s){ unsigned int k; node *p = &Head; int temp; k = 0; for (int i = LENGTH - 1; i>=0 ;i--){ if (((1<<i)&s) != 0){ temp = 0; } else { temp = 1; } if (p->next[temp] == NULL){ k = (k << 1) + (temp ^ 1); p = p->next[temp ^ 1]; } else { k = (k << 1) + temp; p = p->next[temp]; } } return k; } int main(){ int n , m ; unsigned int k , s; Init(); int case_count = 0; scanf("%d", &case_count); int case_index = 0; while ((case_count--) && scanf("%d%d" , &n , &m) != EOF){ case_index++; printf("Case #%d:\n", case_index); Init(); for (int i = 0; i < n; i++){ scanf("%u",&k); insertNode(k); } for (int i = 0; i < m; i++){ scanf("%u" , &s); k = searchNode(s); printf("%u\n" , k); } } return 0; }
Another From:czz5242199@CSDN
给出N个数(N<=10W),然后给出M个数(M<=10W),对于每个数p在之前的N个数中找出q使得 p xor q最大
一步一步考虑即可,首先选择使得p在二进制表示下最高位(第31位)是1的那些数,如果没有再选择会使得最高位为0的数
之后再之后选择的数中选择能够使得第30位为1的数
.......
直到最后
数据结构就选择trie树即可
#include <stdio.h> struct node { struct node *zero, *one; node() { zero = NULL; one = NULL; } }; node *head; long long power[32]; void add(node* &h, int dep, long long p) { if (h == NULL) h = new node(); if (dep == -1) return; if (p&power[dep]) add(h->one, dep-1, p); else add(h->zero, dep-1, p); } long long getAnswer(long long p) { long long ans = 0; node* h = head; for (int i=31; i>=0; i--) { if (p&power[i]) { if (h->zero) { h = h->zero; } else { ans |= power[i]; h = h->one; } } else { if (h->one) { ans |= power[i]; h = h->one; } else { h = h->zero; } } } return ans; } int main() { power[0] = 1; for (int i=1; i<=31; i++) power[i] = power[i-1] << 1; int T, n, m; scanf("%d",&T); for (int test = 0; test < T; ++test) { scanf("%d%d",&n, &m); head = NULL; for (int i = 0; i < n; ++i) { long long temp; scanf("%I64d",&temp); add(head, 31, temp); } printf("Case #%d:\n", test+1); for (int i=0; i<m; i++) { long long temp; scanf("%lld",&temp); printf("%I64d\n", getAnswer(temp)); } } return 0; }
D.Labyrinth (HDU4826) From:czz5242199@CSDN
给一个矩阵,一开始你在左上角,每个格子都有一个数,你可以选择向右,向下,向上走,但不能走重复,问你走到右上角的时候积累的和最大是多少
不能向左走是一个重要的特点,让我们可以使用动态规划
用f[i, j]表示走到第i行j列的时候最多能积累的和
首先f[i,j] = f[i,j-1]+a[i,j] (从左边走过来)
之后由于还可以上下走,所以对当前列上下各用一次动态规划即可,最后答案是f[0, M-1]
#include <iostream> #include <stdio.h> using namespace std; int T, n, m; int a[100][100], f[100][100], t[100]; int max(int a, int b) { return a>b?a:b; } int main() { cin >> T; for (int test=1; test<=T; test++) { cin >> n >> m; for (int i=0; i<n; i++) for (int j=0; j<m; j++) cin >> a[i][j]; cout << "Case #" << test << ":\n"; f[0][0] = a[0][0]; for (int i=1; i<n; i++) f[i][0] = f[i-1][0]+a[i][0]; for (int j=1; j<m; j++) { for (int i=0; i<n; i++) f[i][j] = f[i][j-1]+a[i][j]; t[0] = f[0][j]; for (int i=1; i<n; i++) t[i] = max(f[i][j], t[i-1]+a[i][j]); for (int i=n-2; i>=0; i--) f[i][j] = max(f[i][j], f[i+1][j]+a[i][j]); for (int i=0; i<n; i++) f[i][j] = max(f[i][j], t[i]); } cout << f[0][m-1] << endl; } }
相关文章推荐
- leetCode解题报告之Palindrome Partitioning I,II(DFS,DP)
- 2014百度之星资格赛解题报告:Xor Sum
- 2014 ACM/ICPC 上海赛区网络赛解题报告汇总
- BZOJ 3727 PA2014 树DP 解题报告
- NOIP2014 飞扬的小鸟 解题报告(DP)
- 2014微软编程之美资格赛解题报告
- 2014牡丹江网络赛解题报告
- POJ1191 棋盘分割 ACM解题报告(DFS+DP)
- 2014 ACM/ICPC 广州赛区网络赛解题报告汇总
- BZOJ 3566 [SHOI 2014] 树上期望DP 解题报告
- 2014百度之星资格赛解题报告:Labyrinth
- 2014百度之星资格赛解题报告:Disk Schedule
- 2014百度之星资格赛解题报告:能量变换
- 【百度之星2014~资格赛解题报告】
- leetCode解题报告之Palindrome Partitioning I,II(DFS,DP)
- 2014百度之星资格赛解题报告:Labyrinth
- 【百度之星2014~资格赛解题报告】
- 【百度之星2014~资格赛解题报告】
- NOIP2014 无线网络发射器选址 解题报告(水题)
- NOIP2014 联合权值 解题报告(乱搞(据说这道题是树状dp,感觉好像是))