奇技淫巧训练之四

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\n");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\n");goto end;}
                }
                else 
                if(tmp.r<tmp1.r)
                    q.push((node) {tmp.r+1, tmp1.r, tmp1.s - tmp.s});
            }
            tmp = tmp1;
        }
        printf("true\n");
        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\n"); else printf("false\n");  
    }  
    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;
}
posted @ 2019-10-06 11:00  wzx_believer  阅读(136)  评论(0编辑  收藏  举报