【日记】7.10

今天的考试貌似也有点儿水,最后看了2道题,A了两道、第三题题目描述有点儿问题,直接就没去写……

 

第一题

三元限制最短路
【题目描述】

给定一个包含 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操作

View Code
  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的内存……而且不用的话时间复杂度也有点儿大……

 

第二题

快餐问题
【题目描述】

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

View Code
  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组……

posted @ 2012-07-10 16:31  守護N1身边  阅读(176)  评论(0编辑  收藏  举报