2017.09.24校内训练

T1:个人卫生综合征

题目描述:

每天BBS都要从家里经过城市中的一段路到学校刷五三。城市中一共有n个路口和m条双向道路,每条双向道路都连接着两个路口ai、bi且有一定的时间花费vi。BBS家编号为1,学校编号为n。今天,BBS由于个人卫生综合征导致他很迟才离开家,他想用膜法改变k条道路的长度使通过其的时间花费vi变为0。现在他问你改变道路长度之后他到学校的最小时间花费是多少?

 

输入格式:

 

第一行为三个整数n、m、k,接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个路口和通过其所用的时间。

 

输出格式:

 

一个整数,表示BBS到学校的最小时间花费。

 

 

 

样例输入

样例输出

4 4 1
1 2 10
2 4 10
1 3 1
3 4 100

1

 

 

 

样例解释:

 

更新3->4的道路,最短路线为1->3->4,用时为1+0=1。

 

数据范围:

 

对于100%的数据:1<=n<=10000,1<=m<=50000,1<=k<=20,1<=vi<=1000000。

 

题解:建分层图,然后跑最短路即可。看代码即可理解。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<vector>
 8 #include<queue>
 9 #define inf 0x3f3f3f3f
10 using namespace std;
11 struct path{
12     int to,val;
13 };
14 struct node{
15     int num,v;
16     bool operator <(const node &b) const{
17         return v>b.v;
18     }
19 };
20 std::vector<path> g[10010];
21 std::priority_queue<node> q;
22 int m,n,k,ans;
23 int dist[10010][25];
24 bool vis[10010][25];
25 void dij(){
26     node now;
27     memset(dist,inf,sizeof(dist));
28     memset(vis,0,sizeof(vis));
29     dist[1][0]=0;
30     int i,j;
31     q.push((node){1,0});
32     while(!q.empty()){
33         now=q.top();q.pop();
34         int ta=now.num%(n+1),tb=now.num/(n+1);
35         vis[ta][tb]=true;
36         for(i=0;i<int(g[ta].size());++i){
37             path t=g[ta][i];
38             if(!vis[t.to][tb] && dist[t.to][tb]>dist[ta][tb]+t.val){
39                 dist[t.to][tb]=dist[ta][tb]+t.val;
40                 q.push((node){tb*(n+1)+t.to,dist[t.to][tb]});
41             }
42             if(!vis[t.to][tb+1] && tb<k && dist[t.to][tb+1]>dist[ta][tb]){
43                 dist[t.to][tb+1]=dist[ta][tb];
44                 q.push((node){(tb+1)*(n+1)+t.to,dist[t.to][tb+1]});
45             }
46         }
47     }
48 }
49 int main(){
50     freopen("school.in","r",stdin);
51     freopen("school.out","w",stdout);
52     scanf("%d%d%d",&n,&m,&k);
53     int i,j;
54     int a,b,v;
55     for(i=1;i<=m;++i){
56         scanf("%d%d%d",&a,&b,&v);
57         g[a].push_back((path){b,v});
58         g[b].push_back((path){a,v});
59     }
60     dij();
61     ans=inf;
62     for(i=0;i<=k;++i)  ans=min(ans,dist[n][i]);
63     printf("%d\n",ans);
64     return 0;
65 }
school

 

 

 

 

T2:你的四边形已如风中残烛

题目描述:

LGL有一根长为n的木板。现在他想要把它砍成四段长度为整数的木板来做一个四边形,请问他有多少种不同的砍法?注意:四段长度为1、1、2、1和四段长度为1、2、1、1算两种砍法。

 

输入格式:

 

第一行为一个整数 n,表示木板的长度。

 

输出格式:

 

一个整数,不同的砍法数量。

 

样例输入

样例输出

6

6

 

样例解释:

 

       1122,1212,1221,2112,2121,2211。

 

数据范围:

对于100%的数据:1<=n<=2500。

题解:记dp[i][j]为长度为i时分成j段的方案数,注意一段长度小于总长的一般。dp[i][j]可以从dp[i-k][j-1]转移而来(k表示单段长度)。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 using namespace std;
 8 int n,mid;
 9 int dp[2510][5];
10 int min(int a,int b){
11     return a<b?a:b;
12 }
13 int main(){
14     freopen("quad.in","r",stdin);
15     freopen("quad.out","w",stdout);
16     scanf("%d",&n);
17     memset(dp,0,sizeof(dp));
18     mid=(n-1)>>1;
19     dp[0][0]=1;
20     int i,j,k;
21     for(i=1;i<=n;++i){
22         for(j=1;j<=4;++j){
23             for(k=1;k<=min(i,mid);++k){
24                 dp[i][j]+=dp[i-k][j-1];
25             }
26         }
27     }
28     printf("%d\n",dp[n][4]);
29     return 0;
30 }
View Code

 

 

 

 

T3:生命不息刷题不止

题目描述:

 YYH有n道题要做。但是由于他上课做某些事,导致他一题都不会做,只好请LGL代打。LGL为了买自己心爱的坦克,他做第i题要收两笔钱:一笔在YYH叫他做题当天收,另外一笔在叫他做题的第二天收。YYH每天结束的时候都会把剩下的所有钱花光,然后再从父亲LRB处得到m元零花钱用来请LGL做题(也就是说,第一天的时候YYH是没有钱请LGL做题的,每一天用来请LGL做题所用的钱都是前一天LRB给的)。而且,YYH做的题目难度是循序渐进的:就算强如LGL,在做第i题之前也要先把第1到i-1题全部做完。请问YYH将所有题目做完并且把所有钱都付给LGL的最小天数。

输入格式:

第一行为两个整数m、n,接下来的n行每一行都有两个数ai和bi,分别表示LGL做第i题所收的两笔钱。

输出格式:

一个整数,表示最小天数。

样例输入

样例输出

100 5
40 20
60 20
30 50
30 50
40 40

6

样例解释:

                     第二天做1、2两题,第三天做3、4两题,第五天做5。在第六天的时候所有钱都付完。

数据范围:

对于100%的数据:1<=n<=300,1<=ai、bi<=m<=1000。

题解:记dp[i][j]为前i天做了j道题第i天最多能够剩下的钱的数量。因此,dp[i][j]可以转移到dp[i][j+1],dp[i][j+2]……只要满足剩下的钱大于0且下一天的钱够才行。同时,也可以算出dp[i+1][j+1],dp[i+1][j+2]……最后输出dp[i][m]的最小存在值i即可。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<algorithm>
 7 #define inf 0x3f3f3f3f
 8 using namespace std;
 9 int n,m;
10 int ta,tb;
11 int max(int a,int b){
12     return a>b?a:b;
13 }
14 int dp[1010][310];
15 int a[310],b[310];
16 int main(){
17     freopen("solve.in","r",stdin);
18     freopen("solve.out","w",stdout);
19     scanf("%d%d",&m,&n);
20     int j;
21     for(int i=1;i<=n;++i){
22         scanf("%d%d",&a[i],&b[i]);
23     }
24     memset(dp,inf,sizeof(dp));
25     dp[2][0]=m;
26     int i=2;
27     while(dp[i][n]==inf){
28         for(j=n;j>=0;j--){
29             if(dp[i][j]!=inf){
30                 int k=j+1;
31                 ta=dp[i][j];tb=dp[i+1][j]=m;
32                 while(ta>=a[k] && tb>=b[k]){
33                     ta-=a[k];tb-=b[k];
34                     dp[i][k]=(dp[i][k]==inf?ta:max(dp[i][k],ta));
35                     dp[i+1][k]=(dp[i+1][k]==inf?tb:max(dp[i+1][k],tb));
36                     k++;
37                 }
38             }
39         }
40         i++;
41     }
42     printf("%d\n",i);
43     return 0;
44 }
View Code

 

 

T4:短

题目描述:

给出一张有n个点和m条双向边的图,要求求出1到n的次短路的长度。一条边可以多次通过。

输入格式:

第一行为两个整数n和m。接下来的m行每行三个整数ai,bi,vi,分别表示这条路连着的两个点和他的长度。

输出格式:

一个整数,表示次短路的长度。

样例输入

样例输出

4 4
1 2 100
2 4 200
2 3 250
3 4 100

450

样例解释:

最短:1->2->4。

次短:1->2->3->4。

数据范围:

对于 100%的数据:1<=n、vi<=5000,1<=m<=100000。

题解:考虑dist[i]为1到i的最短路,dist2[i]表示从i到n的最短路次短路有两种情况:一是从1走dist[i]到i,从i到j,走dist2[j]到n;二是从1走dist[i]到i,从i到j再回到i,走dist2[i]到n,暴力枚举即可(似乎dij也有一种算法,但我打挂了)。

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<algorithm>
  5 #include<iostream>
  6 #include<cmath>
  7 #include<queue>
  8 #define inf 0x3f3f3f3f
  9 struct path
 10 {
 11     int from,to,v,next;
 12 }g[200001];
 13 int min(int a,int b){
 14     return a<b?a:b;
 15 }
 16 std::queue<int> q;
 17 int n,m,tot,mn,ans;
 18 int last[5001],dist[5001],dist2[5001];
 19 bool inq[5001];
 20 void ins(int a,int b,int v)
 21 {
 22     g[++tot].from=a;g[tot].to=b;g[tot].v=v;g[tot].next=last[a];last[a]=tot;
 23     g[++tot].from=b;g[tot].to=a;g[tot].v=v;g[tot].next=last[b];last[b]=tot;
 24 }
 25 void spfa()
 26 {
 27     memset(inq,false,sizeof(inq));
 28     memset(dist,inf,sizeof(dist));
 29     dist[1]=0;
 30     q.push(1);
 31     inq[1]=true;
 32     while(!q.empty())
 33     {
 34         int now=q.front();
 35         q.pop();
 36         inq[now]=false;
 37         for(int i=last[now];i>0;i=g[i].next)
 38         {
 39             int t=g[i].to;
 40             if(dist[t]>dist[now]+g[i].v)
 41             {
 42                 dist[t]=dist[now]+g[i].v;
 43                 if(!inq[t])
 44                 {
 45                     q.push(t);
 46                     inq[t]=true;
 47                 }
 48             }
 49         }
 50     }
 51 }
 52 void spfa2()
 53 {
 54     memset(inq,false,sizeof(inq));
 55     memset(dist2,inf,sizeof(dist));
 56     dist2[n]=0;
 57     q.push(n);
 58     inq[n]=true;
 59     while(!q.empty())
 60     {
 61         int now=q.front();
 62         q.pop();
 63         inq[now]=false;
 64         for(int i=last[now];i>0;i=g[i].next)
 65         {
 66             int t=g[i].to;
 67             if(dist2[t]>dist2[now]+g[i].v)
 68             {
 69                 dist2[t]=dist2[now]+g[i].v;
 70                 if(!inq[t])
 71                 {
 72                     q.push(t);
 73                     inq[t]=true;
 74                 }
 75             }
 76         }
 77     }
 78 }
 79 int main()
 80 {
 81     freopen("short.in","r",stdin);
 82     freopen("short.out","w",stdout);
 83     scanf("%d%d",&n,&m);
 84     for(int i=1;i<=m;i++)
 85     {
 86         int x,y,l;
 87         scanf("%d%d%d",&x,&y,&l);
 88         ins(x,y,l);
 89     }
 90     spfa();
 91     mn=dist[n];
 92     spfa2();
 93     ans=inf;
 94     for(int i=1;i<=tot;i++)
 95     {
 96         int l=dist[g[i].from]+dist2[g[i].to]+g[i].v;
 97         if(l<ans&&l>mn) ans=l;
 98     }
 99     for(int i=1;i<=tot;i++)
100         ans=min(ans,dist[g[i].from]+dist2[g[i].from]+2*g[i].v);
101     printf("%d",ans);
102     return 0;
103 }
View Code

 

posted @ 2017-09-26 17:39  lazytear  阅读(205)  评论(0编辑  收藏  举报