日常补题
来源:互联网 发布:黑马程序员每天演讲 编辑:程序博客网 时间:2024/05/17 23:46
CFR 363
给定一个序列:
ai equals 0, if on the i-th day of vacations the gym is closed and the contest is not carried out;
ai equals 1, if on the i-th day of vacations the gym is closed, but the contest is carried out;
ai equals 2, if on the i-th day of vacations the gym is open and the contest is not carried out;
ai equals 3, if on the i-th day of vacations the gym is open and the contest is carried out.
还有个要求:他不会连续两(>=2)天都做相同的运动: (=_=反正就是做活动要间隔像1,2,1,2,1,2)
问最少能休息几天。
dp[i][j]表示第 i 天做 j 类型的活动所能休息的最少时间。
如果x为1,则说明当天能休息或者去GYM,所以更新dp[ i ][1]和dp[ i ][0],同时当天不能做2类型的运动,所以dp[i][2]=INF;其他类型同理,递推下去就好了
/*cf 698A*/#include<stdio.h>#include<algorithm>using namespace std;int D[1005][3];int main(){ //freopen("in.txt","r",stdin); int x,N; scanf("%d", &N); for (int i = 1; i <= N; i++) { scanf("%d",&x); if (x==3) { D[i][0] = min(min(D[i - 1][0], D[i - 1][1]),D[i-1][2])+1; D[i][1] = min(D[i - 1][0], D[i - 1][2]); D[i][2] = min(D[i - 1][0], D[i - 1][1]); } if (x==2) { D[i][0] = min(min(D[i - 1][0], D[i - 1][1]), D[i - 1][2]) + 1; D[i][2] = min(D[i - 1][0], D[i - 1][1]); D[i][1] = 100000000; } if (x==1) { D[i][0] = min(min(D[i - 1][0], D[i - 1][1]), D[i - 1][2]) + 1; D[i][2] = 100000000; D[i][1] = min(D[i - 1][0], D[i - 1][2]); } if (x==0) { D[i][0] = min(min(D[i - 1][0], D[i - 1][1]), D[i - 1][2]) + 1; D[i][1] = 100000000; D[i][2] = 100000000; } } printf("%d\n", min(min(D[N][0], D[N][1]), D[N][2])); return 0;}
CF 698B
给一个数组a,
ai是 i 的父亲。
让你修改最少的元素pi让这数组变成一棵合法的树…
首先,要找出这个数组中有多少个环和多少个根节点( ai== i ) 的.
然后将每个环中的一个点当作这个环的根节点。
然后使用并查集解法是:
先把所有根节点都找出来,并将总的根节点num初始为其中的一个根节点。
再把所有的环都拆开,找出环中的一个点作为根节点a[i]==i。
然后把所有根结点都连向num。
注意: 优先把总根节点num初始化成a[i]==i,而不是拆开的环,因为要找的是操作数最少,找环的话操作次数会+1
这方法也是从CF一个看到的代码那里学习的…
我本来想把这棵树分成几个联通量…再把所有联通量都找出根节点,一 一连起来..
但是不知道怎么把环拆开…
/*并查集*/#include <bits/stdc++.h>using namespace std;const int maxn = 200050;int a[maxn],f[maxn],ans[maxn];int Find(int x){ return f[x] == x?x:f[x] = Find(f[x]);}int main(){#ifdef LOCAL freopen("in.txt","r",stdin);#endif // LOCAL int n; scanf("%d",&n); for(int i = 1; i<=n; i++) f[i] = i; int cnt=0,num=-1;; for(int i = 1; i<=n; i++) { scanf("%d",&a[i]); int x=Find(i),y=Find(a[i]); if(a[i]==i) {num=i,ans[++cnt] = i;continue;}//这是一个根节点 else if(x==y)//ai!=i,而i,a[i]在一个联通块里,此时又要将i连向a[i],所以肯定会出现环。 { a[i]=i;//将所有环都拆开,并以这个点为根节点。 cnt++; } f[x]=y; } if(num==-1)//如果没有找到根节点,再从拆开的环里面找出一个结点当根节点。 { for(int i=1;i<=n;i++) if(a[i]==i) { num=i; cnt++;//只有环的话,改变的元素会多一个。 break; } } printf("%d\n",--cnt); for(int i=1;i<=n;i++) { if(i==a[i]) a[i]=num;//将所有根节点都连向一个根节点num printf("%d%c",a[i],i==n?'\n':' '); }}
BFS解法…其实和并查集差不多..
只是我把每个联通量的根节点都存了起来,再把所有根节点都连向root…
就是BFS判环和并查集判环不同。
/*BFS*/#include <bits/stdc++.h>using namespace std;int f[200006];int circle[200006],cnt,fa[200006];bool vis[200006];vector<int >E[200006];int num=-1,flag=0;int bfs(int x){ queue<int>Q; Q.push(x); int t=0; bool cir=0; while(!Q.empty()) { x=Q.front(); if(f[x]==x) t=x; Q.pop(); for(int i=0;i<E[x].size();i++) { if(!vis[E[x][i]]) { Q.push(E[x][i]); fa[E[x][i]]=x; vis[E[x][i]]=1; } else if(fa[x]!=E[x][i]&&!cir) { if(num==-1) num=x; t=x; cir=1;//标记,免得环里的元素重复出现... } } } return t;//一个联通量里只会有一个根节点或者一个环}int main(){#ifdef LOCAL freopen("in.txt","r",stdin);#endif // LOCAL int n; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&f[i]); if(f[i]==i) flag=1,num=i; E[i].push_back(f[i]); E[f[i]].push_back(i); } for(int i=1;i<=n;i++) { if(!vis[i]) { vis[i]=1;//忘了这句一直WA...MDZZ int k=bfs(i); //cout<<k<<endl; circle[++cnt]=k; } } printf("%d\n",cnt-flag); for(int i=1;i<=cnt;i++) { f[circle[i]]=num; } for(int i=1;i<=n;i++) { printf("%d%c",f[i],i==n?'\n':' '); } return 0;}
蒟蒻加油。
- 日常补题
- 日常补
- 日常总结_2(补八月七日)
- 补题
- 日常刷题系列
- 日常发题
- 刷题日常
- 日常
- 日常
- 【日常】...
- 日常
- 。。。。。日常
- 日常
- 日常
- 日常
- 日常
- 日常
- 日常
- 如何快速删除Linux文件中的重复数据行
- 图像识别技术——验证码识别
- java 垃圾回收机制 finalize System.gc
- 二叉堆C语言实现
- 美丽的茧
- 日常补题
- linux内核中Wifi控制部分的通信框架
- 画板间即时通讯demo
- ROS学习笔记二:探索ROS文件系统
- 数据库表中获取随机数据
- 软件测试基础(一)
- JavaScript学习笔记二十四:操作DOM
- 那些年用node接入微信走过的坑之(四)---微信扫码登录第三方网站
- sequelize(一)