• 奇技淫巧训练之四


    https://www.luogu.org/problem/P2294

    本题有多种解法;

    贪心

    先按左端点为第一排序关键字,再排右端点。

    之后就开始两两比较,如果左端点相等,就比较右端点,

    如果相等,就比较值,如果值不同,就直接输出false,否则输出true,

    如果右端点不等,就把相同的部分抵消掉,把新的区间再压入优先队列。

    直到不能操作,就输出true。

    很神奇这方法过了

    code by std:

    #include<queue>
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 1100
    using namespace std;
    inline void read(int &x)
    {
        x=0;
        int p=1;
        char c=getchar();
        while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
        while(isdigit(c)) {x=(x<<1)+(x<<3)+(c^'0');c=getchar();}
        x*=p;
    
    }
    int n,m;
    struct node
    {
        int l,r,s;
        bool operator < (const node &h)const
        {
            if(l!=h.l)return l>h.l;
            return r>h.r;
        }
    }tmp;
    priority_queue<node>q;
    int main()
    {
        int t;
        read(t);
        while(t--)
        {    
            while (!q.empty()) q.pop();
            read(n);read(m);
            if(m==1){printf("true
    ");continue;}
            for(int i=1;i<=m;i++)
            {
                int l,r,s;
                read(tmp.l);read(tmp.r);read(tmp.s);
                q.push(tmp);
            }
            tmp=q.top();
            q.pop();
            while(!q.empty())
            {    
                node tmp1;
                tmp1=q.top();
                q.pop();
                if(tmp.l==tmp1.l)
                {
                    if(tmp.r==tmp1.r)
                    {
                        if(tmp.s!=tmp1.s)
                        {printf("false
    ");goto end;}
                    }
                    else 
                    if(tmp.r<tmp1.r)
                        q.push((node) {tmp.r+1, tmp1.r, tmp1.s - tmp.s});
                }
                tmp = tmp1;
            }
            printf("true
    ");
            end:;
        }
        return 0;
    }
    

    带权并查集;

    应该不是很好理解(反正我没懂)

    给出[l,r]的区间和,相当于s[r]-s[l]

    一旦已经知道了 s[a]-s[b],s[b]-s[c],显然再给出一条[a,c]就可以判断"账本的真假"了

    将每条这样的信息(l,r,w),l,r放入一个集合中,

    用并查集来维护,并维护cha[l]=s[root]-s[l],cha[r]=s[root]-s[r]

    若 l,r已经在同一个集合中,就直接查询cha[l]-cha[r],判读与w是否相等

    code:

    #include<bits/stdc++.h>
    int fa[105],cha[105];  
    int find(int x)
    {  
        if(x!=fa[x])
        {
            int t=find(fa[x]);
            cha[x]+=cha[fa[x]];
            fa[x]=t;  
        }  
        return fa[x];  
    }  
    int main()  
    {  
        int T,n,m,i,x,y,z,flag;  
        scanf("%d",&T);  
        while (T--) 
        {  
            flag=0;  
            scanf("%d%d",&n,&m);  
            for(i=0;i<=n;i++)
            {  
                fa[i]=i;  
                cha[i]=0;  
            }  
            for(i=1;i<=m;i++)  
            {  
                scanf("%d%d%d",&x,&y,&z);  
                x--;  
                if(find(x)!=find(y))  
                {  
                    cha[fa[y]]=cha[x]-cha[y]-z;  
                    fa[fa[y]]=fa[x];
                }  
                else  
                if(cha[x]-cha[y]!=z) flag=1;  
            }  
            if(flag==0) printf("true
    "); else printf("false
    ");  
        }  
        return 0;  
    }
    

    区间DP

    code(应该很好理解,就是时间有点傻逼O(n三方)):

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    int f[101][101];
    int main()
    {
        int w,n,m,p,s,t,v;
        cin>>w;
        for(int i=1;i<=w;i++)
        {
            memset(f,0,sizeof(f));
            scanf("%d%d",&n,&m);
            for(int j=1;j<=m;j++)
            {
                scanf("%d%d%d",&s,&t,&v);
                f[s][t]=v;
            }
            p=1;
            for(int j=2;j<=n;j++)
            if(p)               
            for(int k=j-1;k>=1;k--)
            if(p)               
            for(int l=k;l<j;l++)    
            if(f[k][l]&&f[l+1][j])
            {
                if(f[k][j])
                {
                    if(f[k][j]!=f[k][l]+f[l+1][j])
                    {
                        p=0;
                        break;
                    }
                }
                else
                f[k][j]=f[k][l]+f[l+1][j];
            }
            if(p==0)
            cout<<"false"<<endl; 
            if(p==1)
            cout<<"true"<<endl;
        }
        return 0;
    }
    

    差分约束

    code(应该算套路吧):

    最好写dfs版的spfa

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    #define MAXN 500
    #define MAXM 4000
    #define MEMINF 0x3f
    struct Edge
    {
        int to,nex,w;
        Edge(){}
        Edge(int _to, int _nex, int _w):to(_to),nex(_nex),w(_w){} 
    };
    Edge e[MAXM+5];
    int first[MAXN+5], dis[MAXN+5], tot, n, m, t, S; 
    bool book[MAXN+5];
    inline void Add(int a, int b, int c)
    {
        e[tot] = Edge(b,first[a],c);
        first[a] = tot++;
        return; 
    }
    bool SPFA(int p)
    {
        book[p] = true;
        for(int u = first[p]; u+1; u = e[u].nex)
            if(dis[e[u].to] > dis[p] + e[u].w)
            {
                dis[e[u].to] = dis[p] + e[u].w;
                if(book[e[u].to] || !SPFA(e[u].to))
                    return false;
            }
        book[p] = false;
        return true;
    }
    inline void Init()
    {
        scanf("%d%d",&n,&m);
        memset(first,-1,sizeof(first));
        memset(dis,MEMINF,sizeof(dis));
        memset(book,false,sizeof(book));
        S = 0, dis[S] = 0, tot = 0;
        for(int s, t, v; m--; )
            scanf("%d%d%d",&s,&t,&v), Add(t,s-1,-v), Add(s-1,t,v);
        return;
    }
    int main()
    {
        for(scanf("%d",&t); t--; puts(SPFA(S) ? "true" : "false"))
            Init();
         return 0;
    }
    
  • 相关阅读:
    实验九——基本数据类型存储及应用总结
    实验八——函数定义及调用总结
    实验7--函数定义及调用总结
    实验五——循环结构学习总结
    实验四—多分支结构及本章总结
    第二次作业及总结——数据类型和运算符
    160809132 梁佳佳
    实验12——指针的基础应用2
    实验11——指针的基础应用
    实验十——一维数组的定义及引用
  • 原文地址:https://www.cnblogs.com/wzxbeliever/p/11626744.html
Copyright © 2020-2023  润新知