日常补题

来源:互联网 发布:黑马程序员每天演讲 编辑:程序博客网 时间: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;}

蒟蒻加油。

0 0