【日记】7.10
今天的考试貌似也有点儿水,最后看了2道题,A了两道、第三题题目描述有点儿问题,直接就没去写……
第一题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
【题目描述】 给定一个包含 N 个点,M 条边的无向图,每条边的边权均为 1。 再给定 K 个三元组(A,B,C) ,表示从 A 点走到 B 点后不能往 C 点走。注意三元组是有序的,如可 以从 B 点走到 A 点再走到 C。 现在你要在 K 个三元组的限制下,找出 1 号点到 N 号点的最短路径,并输出任意一条合法路径,会有 spj (Special Judge) 检查你的输出。 【输人格式】 输入文件第一行有三个数 N,M,K,意义如题目所述。 接下来 M 行每行两个数 A,B,表示 A,B 间有一条边。 再下面 K 行,每行三个数(A,B,C)描述一个三元组。 【输出格式】 输出文件共两行数,第一行一个数 S 表示最短路径长度。 第二行 S+1 个数,表示从 1 到 N 所经过的节点。 【输入样例】 4 4 2 1 2 2 3 3 4 1 3 1 2 3 1 3 4 【输出样例】 4 1 3 2 3 4 【数据规模】 对于 40%的数据满足 N≤10,M≤20,K≤5。 对于 100%的数据满足 N≤3000,M≤20000,K≤100000。
这道题的权值都是1,所以用的BFS就可以了,但是我写的是spfa,用dis[i][j]表示1从i到j的最短路,然后就是最简单的spfa操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 *Prob : patha 3 *Data : 2012-7-10 4 *Sol : SPFA+Hash 5 */ 6 7 #include <set> 8 #include <cstdio> 9 #include <cstring> 10 11 #define MaxN 3010 12 #define MaxE 401000 13 #define oo 20000000 14 15 using namespace std; 16 17 //cannot 18 struct node1 { 19 int y,last,next; 20 } e2[MaxE]; 21 int s[MaxN]; 22 23 //cannot 24 struct node2 { 25 int y,next; 26 } e[MaxE]; 27 28 int n,m,k,totk=0,tot=0; 29 int a[MaxN]; 30 bool v[MaxN][MaxN]; 31 int pre[MaxN][MaxN]; 32 int dis[MaxN][MaxN]; 33 struct { 34 int x,l; 35 }list[200000]; 36 37 //从x到y不能到z 38 void insert(int x,int y,int z) { 39 e2[totk].y = z; e2[totk].last = x; 40 e2[totk].next = s[y]; s[y] = totk; 41 } 42 void insert1(int x,int y) { 43 e[tot].y = y; 44 e[tot].next = a[x]; a[x] = tot; 45 } 46 //x到y后能不能到c 47 bool can(int x,int y,int c) 48 { 49 int tmp = s[y]; 50 for (;tmp;tmp=e2[tmp].next) { 51 if (e2[tmp].last==x&&e2[tmp].y==c) 52 return false; 53 } 54 return true; 55 } 56 57 void spfa() 58 { 59 memset(dis,127,sizeof(dis)); 60 memset(v,false,sizeof(v)); 61 int open = 1, closd = 0; 62 list[1].x = 1; list[1].l = 0; 63 dis[0][1] = 0; pre[0][1] = 0; 64 v[0][1] = true; 65 while (closd<open) { 66 int now = list[++closd].x; 67 int last = list[closd].l; 68 v[last][now] = false; 69 int te = a[now]; 70 for (;te;te=e[te].next) { 71 //可以走 72 int i = e[te].y; 73 if (can(last,now,i)) { 74 if (dis[last][now]+1<dis[now][i]) { 75 dis[now][i] = dis[last][now]+1; 76 pre[now][i] = last; 77 if (!v[now][i]) { 78 v[now][i] = false; 79 list[++open].x = i; 80 list[open].l = now; 81 } 82 } 83 } 84 } 85 } 86 } 87 88 void print(int x,int y) 89 { 90 if (pre[x][y]!=0) print(pre[x][y],x); 91 printf("%d ",x); 92 } 93 94 int main() 95 { 96 freopen("patha.in","r",stdin); 97 freopen("patha.out","w",stdout); 98 99 scanf("%d%d%d",&n,&m,&k); 100 101 int x,y,z; 102 for (int i=1; i<=m; i++) { 103 scanf("%d%d",&x,&y); 104 tot++; insert1(x,y); 105 tot++; insert1(y,x); 106 } 107 for (int i=1; i<=k; i++) { 108 scanf("%d%d%d",&x,&y,&z); 109 totk++; insert(x,y,z); 110 } 111 112 spfa(); 113 114 int ans = oo; 115 for (int i=1; i<=n; i++) 116 if (dis[i][n]<ans) { 117 k = i; 118 ans = dis[i][n]; 119 } 120 printf("%d\n",ans); 121 122 print(k,n); 123 printf("%d\n",n); 124 125 fclose(stdin); fclose(stdout); 126 return 0; 127 }
没什么好说的,唯一要注意的就是用的邻接表,原因是只给了128Mb的内存……而且不用的话时间复杂度也有点儿大……
第二题
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
【题目描述】 Peter最近在R市开了一家快餐店,为了招揽顾客,该快餐店准备推出一种套餐,该套餐由A个汉堡,B个薯条和C个饮料组成。价格便宜。为了提高产量,Peter从著名的麦当劳公司引进了N条生产线。所有的生产线都可以生产汉堡,薯条和饮料,由于每条生产线每天所能提供的生产时间是有限的、不同的,而汉堡,薯条和饮料的单位生产时间又不同。这使得Peter很为难,不知道如何安排生产才能使一天中生产的套餐产量最大。请你编一程序,计算一天中套餐的最大生产量。为简单起见,假设汉堡、薯条和饮料的日产量不超过100个。 【输人格式】 第一行为三个不超过100的正整数A、B、C中间以一个空格分开。 第二行为3个不超过100的正整数p1,p2,p3分别为汉堡,薯条和饮料的单位生产耗时。中间以一个空格分开。 第三行为为一个整数N (0<=0<=10),表示有N条流水线 第四行为N个不超过10000的正整数,其中Ti表示第i条生产流水线每天提供的生产时间,中间以一个空格分开。 【输出格式】 仅一行,即每天套餐的最大产量。 【输入样例】 2 2 2 1 2 2 2 6 6 【输出样例】 1
用的动态规划,然后加的贪心优化,代码里有注释、比较好明白的简单dp
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /** 2 *Prob : meal 3 *Data : 2012-7-10 4 *Sol : dp+贪心 5 */ 6 7 #include <cstdio> 8 #include <cstring> 9 #include <algorithm> 10 #include <cmath> 11 12 #define MaxN 15 13 #define MaxT 100 14 15 int n,a,b,c,p1,p2,p3; 16 int maxa,maxb,maxc; 17 int t[MaxN]; 18 int f[MaxN][MaxT][MaxT]; 19 20 int min(int x,int y) 21 { 22 return x>y?y:x; 23 } 24 int max(int x,int y) 25 { 26 return x>y?x:y; 27 } 28 int min(int x,int y,int z) 29 { 30 int tmp = min(x,y); 31 tmp = min(tmp,z); 32 return tmp; 33 } 34 35 bool can(int i,int j,int k) 36 { 37 if (f[i][j][k]==-1) return false; 38 if (f[i][j][k]>maxc) { 39 if ((j!=maxa)&&((f[i][j][k]-maxc)*p3>p1)) 40 return false; 41 if ((k!=maxb)&&((f[i][j][k]-maxc)*p3>p2)) 42 return false; 43 } 44 return true; 45 } 46 47 int main() 48 { 49 freopen("meal.in","r",stdin); 50 freopen("meal.out","w",stdout); 51 52 scanf("%d%d%d%d%d%d",&a,&b,&c,&p1,&p2,&p3); 53 scanf("%d",&n); 54 for (int i=1; i<=n; i++) 55 scanf("%d",&t[i]); 56 57 //答案上界 58 int maxans = min(MaxT/a,MaxT/b,MaxT/c); 59 //贪心-整套生产,骗分 60 int ans2=0,tot = a*p1+b*p2+c*p3; 61 for (int i=1; i<=n; i++) 62 while ((t[i]>=3*tot)&&ans2<maxans) { 63 t[i] -= tot; 64 ans2 ++; 65 } 66 maxans -= ans2; 67 68 //答案上界 69 int sum = 0; 70 for (int i=1; i<=n; i++) 71 sum += t[i]; 72 maxans = min(maxans,sum/tot); 73 maxa = maxans*a; 74 maxb = maxans*b; 75 maxc = maxans*c; 76 77 memset(f,255,sizeof(f)); 78 f[0][0][0] = 0; 79 //贪心处理答案上界 80 for (int i=0; i<n; i++) 81 for (int j=0; j<=maxa; j++) 82 for (int k=0; k<=maxb; k++) 83 if (can(i,j,k)) { 84 for (int x=0; x<=min(maxa-j,t[i+1]/p1); x++) 85 for (int y=0; y<=min(maxb-k,(t[i+1]-p1*x)/p2); y++) 86 { 87 int z = (t[i+1]-p1*x-p2*y)/p3; 88 f[i+1][j+x][k+y] = max(f[i+1][j+x][k+y],f[i][j][k]+z); 89 } 90 } 91 //答案 92 int ans = 0; 93 for (int j=0; j<=MaxT; j++) 94 for (int k=0; k<=MaxT; k++) { 95 if (f[n][j][k]==-1) continue; 96 int tmp = min(j/a,k/b,f[n][j][k]/c); 97 ans = max(ans,tmp); 98 } 99 100 printf("%d\n",ans+ans2); 101 102 103 fclose(stdin); fclose(stdout); 104 return 0; 105 }
就写了2道题,认为直接AC两道就足够了,但是最后发现最后一题只有5组数据,写裸的直接60+的分……第二题我即便是AC了也没有拉下很多分,在这道题上被3个人反超了……
值得注意的是数据太水了,第二题所有的数加起来挨个除就能过AC……第一题输出1~n直接就是6组……