NOIP 考前 图论练习

Posted yyjxx2010xyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NOIP 考前 图论练习相关的知识,希望对你有一定的参考价值。

LJOJ 1500:

题目:http://www.docin.com/p-601990756.html

Sol:贪心,从叶子结点往上加入无法传递了,就需要建设。 Dfs返回的是到达叶子节点最多所要的能量,如果大于最大能量就需要建设放大器.

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 const int Maxn=100100;
 6 using namespace std;
 7 int head[Maxn],vis[Maxn],cnt,Ans,x,v,w,n,Power;
 8 struct EDGE{int to,next,w;}edge[Maxn<<2];
 9 inline void Add(int u,int v,int w) {edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w;head[u]=cnt++;}
10 inline int Max(int x,int y) {return x>y?x:y;}
11 int Dfs(int u)
12 {
13     int Res=0; vis[u]=true;
14     for (int i=head[u];i!=-1;i=edge[i].next)
15         if (!vis[edge[i].to])
16         {
17             int Tmp=Dfs(edge[i].to);
18             if (Tmp+edge[i].w>=Power) {if (edge[i].w>Res) Res=edge[i].w; Ans++;}
19             else if (Tmp+edge[i].w>Res) Res=Tmp+edge[i].w;
20         }
21     return Res;
22 }
23 int main()
24 {
25     scanf("%d",&n); int Mx=0;
26     cnt=0; memset(head,-1,sizeof(head)); Ans=0;
27     for (int i=1;i<=n;i++)
28     {
29         scanf("%d",&x);
30         for (int j=1;j<=x;j++)
31         {
32             scanf("%d%d",&v,&w);
33             Add(i,v,w),Add(v,i,w);  Mx=Max(Mx,w);
34         }
35     }
36     scanf("%d",&Power); 
37     if (Mx>=Power) {puts("No solution."); return 0;}
38     Dfs(1);
39     printf("%d\\n",Ans);
40     return 0;
41 }
C++

 

LJOJ 1501: 

题目描述
  出于最高安全性考虑,司令部采用了特殊的安全操作系统,该系统采用一个特殊的文件系统。在这个文件系统中所有磁盘空间都被分成了相同尺寸的N块,用整数1到N标识。每个文件占用磁盘上任意区域的一块或多块存储区,未被文件占用的存储块被认为是可使用的。如果文件存储在磁盘上自然连续的存储块中,则能被以最快的速度读出。   因为磁盘是匀速转动的,所以存取上面不同的存储块需要的时间也不同。读取磁盘开头处的存储块比读取磁盘结尾处的存储块快。根据以上现象,我们事先将文件按其存取频率的大小用整数1到K标识。按文件在磁盘上的最佳存储方法,1号文件将占用1,2,…,S1的存储块,2号文件将占用S1+1,S1+2,...,S1+S2的存储块,以此类推(Si是被第i个文件占用的存储块的个数)。为了将文件以最佳形式存储在磁盘上,需要执行存储块移动操作。一个存储块移动操作包括从磁盘上读取一个被占用的存储块至内存并将它写入其它空的存储块,然后宣称前一个存储块被释放,后一个存储块被占用。   本程序的目的是通过执行最少次数的存储块移动操作,将文件按最佳方式存储到磁盘上,注意同一个文件的存储块在移动之后其相对次序不可改变。
输入
  每个磁盘说明的第一行包含两个用空格隔开的整数N和K,1<=K<=N<=100000,接下来的K行每行说明一个文件,对第i个文件的说明是这样的:首先以整数Si开头,表示第i个文件的存储块数量,1<=Si<=N-K,然后跟Si个整数,每个整数之间用空格隔开,表示该文件按自然顺序在磁盘上占用的存储块的标识。所有这些数都介于1和N之间,包括1和N。   一个磁盘说明中所有存储块的标识都是不同的,并且该盘至少有一个空的存储块。
输出
  对于每一个磁盘说明,只需输出一行句子"We need M move operations",M表示将文件按最佳方式存储到磁盘上所需进行的最少存储块移动操作次数。如果文件已按最佳方式存储,仅需输出“No optimization needed.”。
样例输入
20 3
4 2 3 11 12
1 7
3 18 5 10
样例输出
We need 9 move operations.
题目

Sol:环需要有多余的一块进行交换,不然会覆盖

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int cnt,mb[100001],n,k,p,x,v[100001];
 6 int work(int x)
 7 {
 8     if (mb[x]==x) return 0;
 9     int p=x,t=x,tot=0;v[p]=1;
10     while (1)
11     {
12         p=mb[p];
13         tot++;
14         if (p!=t && p!=0 && v[p]) return tot;
15         v[p]=1;
16         if (p==0) return tot-1;
17         if (p==t) return tot+1;
18   
19     }
20 }
21 int main()
22 {
23     scanf("%d%d",&n,&k);
24     for (int i=1;i<=k;i++)
25     {
26         scanf("%d",&p);
27         for (int i=1;i<=p;i++)
28         {
29             scanf("%d",&x);
30             mb[++cnt]=x;
31         }
32     }
33     int ans=0;
34     for (int i=1;i<=cnt;i++) if (!v[i]) ans+=work(i);
35     if (ans==0) printf("No optimization needed.");
36     else printf("We need %d move operations.\\n",ans);
37 }
C++


LJOJ 1502:

题目:删去一条边使得最短路最长

Sol:Dij后找到最短路,依次删去最短路上的边进行最短路即可

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <vector>
 6 #include <queue>
 7 #define Pa pair<int,int>
 8 #define mp make_pair
 9 using namespace std;
10 const int Inf=0x3f3f3f3f;
11 const int Maxn=1010;
12 const int Maxm=1000100;
13 priority_queue<Pa,vector<Pa>,greater<Pa> > Q;
14 struct EDGE{int to,next,w;}edge[Maxm<<2];
15 int head[Maxn],Dis[Maxn],vis[Maxn],n,m,u,v,w,cnt,Pre[Maxn],Ans,Ban,Ban_Edge[Maxn];
16 inline void Add(int u,int v,int w) {edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w; head[u]=cnt++;} 
17 int Dij(int Flag)
18 {
19     memset(vis,false,sizeof(vis));
20     for (int i=1;i<=n;i++) Dis[i]=Inf;
21     Dis[1]=0; Q.push(mp(0,1));
22     while (!Q.empty())
23     {
24         int u=Q.top().second; Q.pop();
25         if (vis[u]) continue; vis[u]=true;
26         for (int i=head[u];i!=-1;i=edge[i].next) 
27             if (!vis[edge[i].to] && Dis[edge[i].to]>Dis[u]+edge[i].w && Ban!=i && Ban!=(i^1))
28             {
29                 Dis[edge[i].to]=Dis[u]+edge[i].w;
30                 Q.push(mp(Dis[edge[i].to],edge[i].to));
31                 if (Flag) Pre[edge[i].to]=u,Ban_Edge[edge[i].to]=i;
32             }
33     }
34     return Dis[n];
35 }
36 int main()
37 {
38     // freopen("c.in","r",stdin);
39     scanf("%d%d",&n,&m); memset(head,-1,sizeof(head));
40     for (int i=1;i<=m;i++)   scanf("%d%d%d",&u,&v,&w),Add(u,v,w),Add(v,u,w); 
41     Ban=Inf;
42     Dij(true);  Ans=0;
43     u=n;
44     while (true)
45     {
46         Ban=Ban_Edge[u];
47         int Tmp=Dij(false);
48         if (Tmp>Ans) Ans=Tmp;
49         u=Pre[u];
50         if (u==1) break;
51     }
52     printf("%d\\n",Ans);
53     return 0;
54      
55 }
C++

 

LJOJ 1503

题目:经典网络流:Pig

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #define Inf 1<<29
 6 using namespace std;
 7 const int Maxn=110;
 8 struct node
 9 {
10     int to,next,w;
11 }edge[4000000];
12 int cnt,Level[Maxn<<8],pigs[Maxn<<8],Q[4000000],head[Maxn<<8],n,m,Pre[Maxn<<8],limit;
13 inline void Add(int u,int v,int w)
14 {
15     edge[cnt].to=v;
16     edge[cnt].next=head[u];
17     edge[cnt].w=w;
18     head[u]=cnt++;
19     edge[cnt].to=u;
20     edge[cnt].next=head[v];
21     edge[cnt].w=0;//写成w
22     head[v]=cnt++;
23 }
24  
25 inline int Min(int a,int b){return a>b?b:a;}
26 bool Bfs()
27 {
28     memset(Level,-1,sizeof(Level));
29     int l=1,r=1; 
30     Q[1]=0;Level[0]=0;
31     while (l<=r)
32     {
33         int u=Q[l++];
34         for (int i=head[u];i!=-1;i=edge[i].next)
35             if (Level[edge[i].to]==-1 && edge[i].w>0)
36             {
37                 Level[edge[i].to]=Level[u]+1;
38                 Q[++r]=edge[i].to;
39             }
40     }
41     if (Level[n+1]>0) return true;
42     return false;
43 }
44  
45 int Find(int u,int low)
46 {
47     if (u==n+1) return low;
48     int tmp=0;
49     for (int i=head[u];i!=-1;i=edge[i].next)
50     {
51         int v=edge[i].to;
52         if (edge[i].w>0
53             && Level[v]==Level[u]+1
54             && (tmp=Find(v,Min(low,edge[i].w))))
55         {
56             edge[i].w-=tmp,edge[i^1].w+=tmp;
57             return tmp;
58         }
59     }
60     Level[u]=-1;
61     return 0;
62 }
63  
64 int main()
65 {
66 scanf("%d%d",&m,&n);
67         memset(Pre,0,sizeof(Pre));
68         memset(head,-1,sizeof(head));
69         cnt=0;
70         for (int i=1;i<=m;i++) scanf("%d",&pigs[i]);
71         for (int i=1;i<=n;i++)
72         {
73             int tn;
74             scanf("%d",&tn);
75             int sum=0;
76             for (int j=1;j<=tn;j++)
77             {
78                 int x;
79                 scanf("%d",&x);
80                 if (Pre[x]==0)
81                     sum+=pigs[x]; else
82                     Add(Pre[x],i,Inf);
83                 Pre[x]=i;
84             }
85             if (sum!=0) Add(0,i,sum);
86             scanf("%d",&limit);
87             Add(i,n+1,limit);
88         }
89         int ans=0,temp;
90         while (Bfs())
91             while (temp=Find(0,0x7fffffff))
92                 ans+=temp;
93         printf("%d\\n",ans);
94     return 0;
95 }
96  
C++

 

LJOJ 1504

题目: Codevs 3637

Sol:显然不可能形成三角形,假设每点左边的边小于右边的边,会矛盾,然后用Prim就可以了.

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 using namespace std;
 5   
 6 const int MAXN=5010;
 7 const int INF=1e8;
 8   
 9 struct point{
10     int x,y;
11     point(){}
12     point(int x,int y):x(x),y(y){}
13 };
14   
15 int n;
16 point p[MAXN];
17 double ans=0,d[MAXN];
18 bool vis[MAXN]={0};
19   
20 double dist(point a,point b){
21     return sqrt((double)(a.x-b.x)*(double)(a.x-b.x)+(double)(a.y-b.y)*(double)(a.y-b.y));
22 }
23   
24 int main(){
25     scanf("%d",&n);
26     for(int i=1;i<=n;i++){
27         scanf("%d%d",&p[i].x,&p[i].y);
28         d[i]=INF;
29     }
30     d[1]=0;
31     for(int k,i=1;i<=n;i++){
32         double mi=INF;
33         for(int j=1;j<=n;j++){
34             if(!vis[j]&&mi>d[j]){
35                 mi=d[j];
36                 k=j;
37             }
38         }
39         if(mi==INF)break;
40         vis[k]=1;
41         ans+=mi;
42         for(int j=1;j<=n;j++){
43             if(!vis[j]){
44                 d[j]=min(d[j],dist(p[j],p[k]));
45             }
46         }
47     }
48     printf("%.2lf\\n",ans);
49     return 0;
50 }
C++

 

LJOJ 1505

 1 题目描述
 2   在这个繁忙的社会中,我们往往不再去选择最短的道路,而是选择最快的路线。开车时每条道路的限速成为最关键的问题。不幸的是,有一些限速的标志丢失了,因此你无法得知应该开多快。一种可以辩解的解决方案是,按照原来的速度行驶。你的任务是计算两地间的最快路线。   你将获得一现代化城市的道路交通信息。为了使问题简化,地图只包括路口和道路。每条道路是有向的,只连接了两条道路,并且最多只有一块限速标志,位于路的起点。两地A和B,最多只有一条道路从A连接到B。你可以假设加速能够在瞬间完成并且不会有交通堵塞等情况会影响你。当然,你的车速不能超过当前的速度限制。
 3 输入
 4   输入文件SPEED.IN的第一行是3个整数 N,M和D,2<=N<=150,表示道路的数目,用0..N-1标记。M是道路的总数,D表示你的目的地。接下来的M行,每行描述一条道路,每行有4个整数A (0 <= A < N), B (0 <= B < N), V (0 <= V <= 500) and L (1<= L <= 500),这条路是从A到B的,速度限制是V,长度为L。如果V是0,表示这条路的限速未知。如果V不为0,则经过该路的时间T=L/V。否则T = L / Vold,Vold是你到达该路口前的速度。开始时你位于0点,并且速度为70。
 5 输出
 6   输出文件SPEED.OUT仅一行整数,表示从0到D经过的城市。输出的顺序必须按照你经过这些城市的顺序,以0开始,以D结束。仅有一条最快路线。
 7 样例输入
 8 6 15 1
 9 0 1 25 68
10 0 2 30 50
11 0 5 0 101
12 1 2 70 77
13 1 3 35 42
14 2 0 0 22
15 2 1 40 86
16 2 3 0 23
17 2 4 45 40
18 3 1 64 14
19 3 5 0 23
20 4 1 95 8
21 5 1 0 84
22 5 2 90 64
23 5 3 36 40
24 样例输出
25 0 5 2 以上是关于NOIP 考前 图论练习的主要内容,如果未能解决你的问题,请参考以下文章

NOIP 考前 暴力练习

NOIp 2016 总结

NOIP考前临时抱佛脚(算是考前日记吧)

NOIP考纲总结+NOIP考前经验谈

noip2017考前整理(未完)

NOIP 考前 队列复习