模板合集

线段树

1.区间加和区间查询

#include<iostream>
#include<cstdio>
#define maxN 1000010
#define in(x) x=read()
#define ls k<<1
#define rs k<<1 | 1
#define mid ((l+r)>>1)
using namespace std;
typedef long long rd;
typedef long long ll;
ll sum[maxN*4+1],v[maxN*4+1];
int n,m,op,x,y;
inline rd read();
void pushdown(int,int,int),pushup(int);
void build(int,int,int);
ll query(int,int,int,int,int);
void update(int,int,int,int,int,int);
int main()
{
    in(n); in(m); build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        in(op); in(x); in(y);
        if(op==1) update(1,1,n,x,y,read());
        else printf("%lld\n",query(1,1,n,x,y));
    }
    return 0;
}
void pushup(int k) {sum[k]=sum[ls]+sum[rs];}
void pushdown(int k,int l,int r)
{
    v[ls]+=v[k]; v[rs]+=v[k];
    sum[ls]+=(mid-l+1)*v[k];
    sum[rs]+=(r-mid)*v[k];
    v[k]=0;
}
void update(int k,int l,int r,int ql,int qr,int u)
{
    if(ql<=l && r<=qr)
    {
        sum[k]+=u*(r-l+1);
        v[k]+=u; return;
    }
    if(v[k]) pushdown(k,l,r);
    if(ql<=mid) update(ls,l,mid,ql,qr,u);
    if(qr>mid) update(rs,mid+1,r,ql,qr,u);
    pushup(k);
}
long long query(int k,int l,int r,int ql,int qr)
{
    if(ql<=l && r<=qr) return sum[k];
    long long ans=0;
    if(v[k]) pushdown(k,l,r);
    if(ql<=mid) ans+=query(ls,l,mid,ql,qr);
    if(qr>mid) ans+=query(rs,mid+1,r,ql,qr);
    return ans;
}
void build(int k,int l,int r)
{
    if(l==r) {in(sum[k]); return;}
    build(ls,l,mid); build(rs,mid+1,r);
    pushup(k);
}
inline rd read()
{
    rd num=0,f=1;
    char ch=getchar();
    while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    if(ch=='-') {ch=getchar(); f=-1;}
    while(ch>='0' && ch<='9')
    {
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

2.区间加、乘和区间查询

#include<iostream>
#include<cstdio>
#define maxN 100010
#define in(x) x=read()
#define ls k<<1
#define rs k<<1 | 1
#define mid ((l+r)>>1)
#define m(x,y) x=(x*y)%p
#define a(x,y) x=(x+y)%p
using namespace std;
typedef long long rd;
typedef long long ll;
inline rd read();
int n,m,x,y,op;
ll p,va[4*maxN+1],vm[4*maxN+1],sum[4*maxN+1];
void pushup(int);
void build(int,int,int);
void update_1(int,int,int,int,int,int);
void update_2(int,int,int,int,int,int);
ll query(int,int,int,int,int);
void pushdown(int,int,int);
int main()
{
    in(n); in(m); in(p);
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        in(op); in(x); in(y);
        switch(op)
        {
            case 1:update_2(1,1,n,x,y,read()); break;
            case 2:update_1(1,1,n,x,y,read()); break;
            case 3:printf("%lld\n",query(1,1,n,x,y)); break;
        }
    }
    return 0;
}
void build(int k,int l,int r)
{
    va[k]=0; vm[k]=1;
    if(l==r) {in(sum[k]); return;}
    build(ls,l,mid); build(rs,mid+1,r);
    pushup(k);
}
void pushup(int k) {sum[k]=(sum[ls]+sum[rs])%p;}
void update_1(int k,int l,int r,int ql,int qr,int u)
{
    if(ql<=l && r<=qr)
    {
        a(sum[k],u*(r-l+1));
        a(va[k],u); return;
    }
    if(vm[k]!=1 || va[k]) pushdown(k,l,r);
    if(ql<=mid) update_1(ls,l,mid,ql,qr,u);
    if(qr>mid) update_1(rs,mid+1,r,ql,qr,u);
    pushup(k);
}
void update_2(int k,int l,int r,int ql,int qr,int u)
{
    if(ql<=l && r<=qr)
    {
        m(sum[k],u); m(va[k],u);
        m(vm[k],u); return;
    }
    if(vm[k]!=1 || va[k]) pushdown(k,l,r);
    if(ql<=mid) update_2(ls,l,mid,ql,qr,u);
    if(qr>mid) update_2(rs,mid+1,r,ql,qr,u);
    pushup(k);
}
long long query(int k,int l,int r,int ql,int qr)
{
    if(ql<=l && r<=qr) return sum[k]%p;
    long long ans=0;
    if(vm[k]!=1 || va[k]) pushdown(k,l,r);
    if(ql<=mid) ans+=query(ls,l,mid,ql,qr);
    if(qr>mid) ans+=query(rs,mid+1,r,ql,qr);
    return ans%p;
}
void pushdown(int k,int l,int r)
{
    m(vm[ls],vm[k]); m(vm[rs],vm[k]);
    m(va[ls],vm[k]); m(va[rs],vm[k]);
    m(sum[ls],vm[k]); m(sum[rs],vm[k]);
    vm[k]=1;
    a(va[ls],va[k]); a(va[rs],va[k]);
    a(sum[ls],va[k]*(mid-l+1));
    a(sum[rs],va[k]*(r-mid));
    va[k]=0;
}
inline rd read()
{
    rd num=0,f=1;
    char ch=getchar();
    while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    if(ch=='-') {ch=getchar(); f=-1;}
    while(ch>='0' && ch<='9')
    {
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

排列组合

排列:有序且不重复:\(P_n^m=A_n^m=\frac{n!}{(n-m)!}\)
组合:无序且不重复:\(C_n^m=\frac{n!}{(n-m)!m!}\)
推广:二项式定理

\[(x+y)^n=C_n^0x^ny^0+C_n^1x^{n-1}y^1+⋯+C_n^{n-1}x^1y^{n-1}+C_n^nx^0y^n=\sum_{k=0}^nC_n^kx^{n-k}y^k=\sum_{k=0}^nC_n^kx^ky^{n-k} \]

其中二次项系数符合杨辉三角
\(\sum_{k=0}^{n}C_n^{k}\)\(k\) 为偶数):

分析:在二项式定理中,取\(x=1,y=1\)\(x=1,y=-1\)

则:

\[(1+1)^n=C_n^01^n1^0+C_n^11^{n-1}1^1+⋯+C_n^{n-1}1^11^{n-1}+C_n^n1^01^n=\sum_{i=0}^{n}C_n^i=2^n \]

\[(1-1)^n=C_n^0-C_n^1+⋯+(-1)^nC_n^n=\sum_{i=0}^{n}(-1)^iC_n^i \]

两式相加,得\(\sum_{k=0}^{n}C_n^{k}=2^{n-1}\)

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
long long ans();
int main()
{
	int t; scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%d",&n);
		printf("%lld\n",ans());
	}
	return 0;
}
long long ans()
{
	int sum=0;
	for(int i=2;i<=n;i++)
		while(n%i==0)
		{
			n/=i; sum++;
		}
	if(sum) return sum;
	else return 1;
}

唯一分解定理

任何大于1的自然数,都可以唯一分解成有限个质数的乘积
公式(\(p_i\)为质数):

\[n=p_1^{a_1}p_2^{a_2}⋯p_k^{a_k}=\prod_{i=1}^kp_i^{a_i} \]

推广:

正质因数个数为\(\delta(n)=(1+a_1)(1+a_2)⋯(1+a_k)\)
它的全体正因数之和为\(\delta(n)=(1+p_1+p_1^2+⋯+p_1^{a_1})⋯(1+p_k+p_k^2+⋯+p_k^{a_k})\)
\(\delta(n)=2n\)时就称 N 为完全数。是否存在奇完全数,是一个至今未解决之猜想。
欧拉函数:小于n的正整数中与n互质的数的数目

\[\varphi(x)=x\prod_{i=1}^n(1-\frac{1}{p_i}) \]

其中 \(\varphi(1)=1\)


质因数分解:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n;
long long ans();
int main()
{
	int t; scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		scanf("%d",&n);
		printf("%lld\n",ans());
	}
	return 0;
}
long long ans()
{
	int sum=0;
	for(int i=2;i<=n;i++)
		while(n%i==0)
		{
			n/=i; sum++;
		}
	if(sum) return sum;
	else return 1;
}

快速读入

#define in(x) x=read()
typedef int rd;
inline rd read();

inline rd read()
{
    rd num=0,f=1;
    char ch=getchar();
    while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    if(ch=='-') {ch=getchar(); f=-1;}
    while(ch>='0' && ch<='9')
    {
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

单源最短路径

  1. SPFA
#include<cstdio>
using namespace std;
const int maxN=10000,maxL=500000,inf=2147483647;
struct Node
{
    int from,to,value,next;
}edge[maxN+1];
int head[maxL+1],dis[maxL+1],tot=0,n,m,s,q[maxL*2+1];
bool flag[maxL+1];
void add_edge(int x,int y,int t)
{
    tot++;
    edge[tot].from=x;
    edge[tot].to=y;
    edge[tot].value=t;
    edge[tot].next=head[x];
    head[x]=tot;
}
void SPFA()
{
    int q_head=0,q_tail=0;
    q[q_tail++]=s;
    flag[s]=true;
    while(q_head!=q_tail)
    {
        int x=q[q_head];
        flag[x]=false;
        for(int i=head[x];i;i=edge[i].next)
            if(dis[x]+edge[i].value<dis[edge[i].to])
            {
                dis[edge[i].to]=dis[x]+edge[i].value;
                if(!flag[edge[i].to])
                {
                    flag[edge[i].to]=true;
                    q[q_tail++]=edge[i].to;
                    if(q_tail>n) q_tail=0;
                }
            }
        q_head++;
        if(q_head>n) q_head=0;
    }
}
int main()
{
    scanf("%d%d%d",&n,&m,&s);
    for(int i=1;i<=n;i++) dis[i]=inf;
    for(int i=0;i<m;i++)
    {
        int x,y,t;
        scanf("%d%d%d",&x,&y,&t);
        add_edge(x,y,t);
    }
    dis[s]=0;
    SPFA();
    for(int i=1;i<=n;i++)
		printf("%d ",dis[i]);
    return 0;
}
  1. Dijkstra
    1、朴素算法
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxN=10000,maxM=500000,INF=2147483647;
bool b[maxN+1];
int head[maxN+1],n,x,y,tot,m,s,e,dist,fr,minl,c[maxN+1];
struct Node
{
	int value,from,to,next; 
}edge[maxM+1];
void addedge(int,int,int);
int main()
{
	scanf("%d %d %d",&n,&m,&s);
	for(int i=1;i<=maxN;i++) c[i]=edge[i].value=INF;
	for(int i=maxN+1;i<=maxM;i++) edge[i].value=INF;
	memset(b,false,sizeof(b));
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d %d",&x,&y,&dist);
		addedge(x,y,dist);
	}
	for(int i=head[s];i;i=edge[i].next) c[edge[i].to]=edge[i].value;
	b[s]=true; c[s]=0;
	int k=s;
	for(int i=1;i<=n-1;i++)
	{
		for(int j=head[k];j;j=edge[j].next)
			if(c[k]+edge[j].value<c[edge[j].to])
				c[edge[j].to]=c[k]+edge[j].value;
		minl=INF; k=0;
		for(int j=1;j<=n;j++)
			if(!b[j] && (c[j]<minl))
				{minl=c[j]; k=j;}
		if(k==0) break;
		b[k]=true;
	}
	for(int i=1;i<=n;i++)
		printf("%d ",c[i]);
	return 0;
}
void addedge(int x,int y,int value)
{
	tot++;
	edge[tot].from=x;
	edge[tot].to=y;
	edge[tot].value=min(value,edge[tot].value);
	edge[tot].next=head[x];
	head[x]=tot;
}

2、堆优化

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
const int maxN=100000,maxM=200000;
int head[maxN+1],n,m,s,dis[maxN+1],tot=0;
bool vis[maxN+1];
struct Node
{
	int value,from,to,next; 
}edge[maxM+1];
inline int read();
void addedge(int,int,int);
void dijkstra(int);
priority_queue<pair<int,int> > q;
int main()
{
	n=read(); m=read(); s=read();
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
        x=read(); y=read(); z=read();
		addedge(x,y,z);
	}
    dijkstra(s);
	for(int i=1;i<=n;i++)
        printf("%d ",dis[i]);
	return 0;
}
inline int read()
{
    char ch=getchar();
    int num=0,f=1;
    while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    if(ch=='-') {f=-1; ch=getchar();}
    while(ch>='0' && ch<='9')
    {
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}
void addedge(int x,int y,int value)
{
	tot++;
	edge[tot].from=x;
	edge[tot].to=y;
	edge[tot].value=value;
	edge[tot].next=head[x];
	head[x]=tot;
}
void dijkstra(int s)
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,false,sizeof(vis));
    dis[s]=0;
    q.push(make_pair(0,s));
    while(q.size())
    {
        int x=q.top().second;
        q.pop();
        if(vis[x]) continue;
        vis[x]=true;
        for(int i=head[x];i;i=edge[i].next)
        {
            if(dis[edge[i].to]>dis[x]+edge[i].value)
            {
                dis[edge[i].to]=dis[x]+edge[i].value;
                q.push(make_pair(-dis[edge[i].to],edge[i].to));
            }
        }
    }
}

  1. Floyed-Warshell
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxN=500,INF=2147483647;
int n,x,y,tot,m,s,e,dist,fr,minl,c[maxN+1][maxN+1];
int main()
{
	scanf("%d %d %d",&n,&m,&s);
	memset(c,0x3f,sizeof(c));
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d %d",&x,&y,&dist);
		c[x][y]=c[y][x]=dist;
	}
	for(int k=1;k<=n;k++)
		for(int i=1;i<=n;i++)
			for(int j=1;j<=n;j++)
				if(c[i][j]>c[i][k]+c[k][j])
					c[i][j]=c[i][k]+c[k][j];
	c[s][1]=0;
	for(int i=1;i<=n;i++)
		printf("%d ",c[s][i]);
	return 0;
}

RMQ

RMQ,区间最小(大)值查询
对于长度为 \(n\) 的数列 \(A\) ,求出其中下标在 \(i,j\) 之间的最小(大)值
时间复杂度:预处理 \(O(n^2)\) , 查询 \(O(1)\)

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxN=100000;
int a[maxN+1],f[maxN+1][20],n,m;
void init();
void out(int,int);
int read();
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    	a[i]=read();
    init();
    for(int i=1;i<=m;i++)
    {
    	int l,r;
    	l=read(); r=read();
    	out(l,r);
    }
    return 0;
}
void init()
{
    for(int i=1;i<=n;i++)
        f[i][0]=a[i];
    int l=(int)(log(n)/log(2));
    for(int j=1;j<=l;j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
}
int read()
{
    int temp=0,f=1;
    char ch=getchar();
    while((ch<'0' || ch>'9') && ch!='-') ch=getchar();
    if(ch=='-') {f=-1; ch=getchar();}
    while(ch>='0' && ch<='9')
    {
        temp=temp*10+ch-'0';
        ch=getchar();
    }
    return temp*f;
}
void out(int l,int r)
{
    int k=0,x=r-l+1;
    k=(int)(log(x)/log(2));
    printf("%d\n",max(f[l][k],f[r-(1<<k)+1][k]));
}

最长公共子序列

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxN=100000;
int a[maxN+1],val[maxN+1];
int dp[maxN+1],n,LIS(int[],int);
int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        val[a[i]]=i;
    }
    for(int i=0;i<n;i++)
    {
        scanf("%d",&a[i]);
        a[i]=val[a[i]];
    }
    printf("%d",LIS(a,n));
    return 0;
}
int LIS(int num[],int n)
{
    int ans=1;
    memset(dp,0,sizeof(dp));
    dp[0]=num[0];
    for(int i=1;i<n;i++)
    {
        int j=upper_bound(dp,dp+ans,num[i])-dp;
        if(j<ans) dp[j]=num[i];
        else dp[ans++]=num[i];
    }
    return ans;
}


归并排序(逆序对)

#include<iostream>
#include<cstdio>
const int maxN=40000;  
using namespace std;  
int temp[maxN+1],num[maxN+1],n;  
int sum=0; //sum求逆序对个数 
void Merge(int a[],int l,int mid,int r)  
{  
    int i=l,j=mid+1,tot=l;
    while(i<=mid && j<=r)
        if(a[i]>a[j])
        {  
        	temp[tot++]=a[j++];
        	//sum+=mid-i+1;
        }
        else temp[tot++]=a[i++];
    while(j<=r) temp[tot++]=a[j++];
    while(i<=mid) temp[tot++]=a[i++];
    for(int k=l;k<=r;k++)
        a[k]=temp[k];
}
void mergesort(int a[],int l,int r)
{
    if(l<r)
    {
        int mid=(l+r)/2;
        mergesort(a,l,mid);
        mergesort(a,mid+1,r);
        Merge(a,l,mid,r);
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&num[i]);
    mergesort(num,1,n);
    for(int i=1;i<=n;i++)
    	printf("%d ",num[i]);
    //printf("%d",sum);
    return 0;
}

堆排序

#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=10000;
int heap[maxN+1],len=0,n;
void put(int);
int get();
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int x; scanf("%d",&x);
		put(x);
	}
	for(int i=n;i>=1;i--)
		heap[i]=get();
	for(int i=1;i<=n;i++)
		printf("%d ",heap[i]);
	return 0;
}
void put(int x)
{
	int son,pa;
	son=++len;
	heap[son]=x;
	while(son>1)
	{
		pa=son>>1;
		if(heap[pa]>=heap[son]) break;
		swap(heap[pa],heap[son]);
		son=pa;
	}
}
int get()
{
	int son,pa=1,ans=heap[1];
	heap[pa]=heap[len--];
	while(pa*2<=len)
	{
		son=pa<<1;
		if(son<len && heap[son+1]>heap[son]) son++;
		if(heap[pa]>=heap[son]) break;
		swap(heap[pa],heap[son]);
		pa=son; 
	}
	return ans;
}

快速排序

#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=100000;
void quicksort(int,int);
void change(int&,int&);
int n,a[maxN+1];
int main()
{
    bool flag=true;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    quicksort(1,n); //STL:sort(a+1,a+n+1); 
    for(int i=1;i<=n;i++)
        printf("%d ",a[i]);
    return 0;
}
void quicksort(int l,int r)
{
    if(l>r) return;
    int i,j,temp,mid=(l+r)/2;
    temp=a[mid]; i=l; j=r;
    while(i<j)
    {
        while(a[i]<temp) i++;
        while(a[j]>temp) j--;
        if(i<=j)
        {
            a[0]=a[i];
            swap(a[i],a[j]);
            i++; j--;
        }
    }
    if(l<j) quicksort(l,j);
    if(i<r) quicksort(i,r);
    return;
}

并查集

#include<iostream>
#include<cstdio>
#include<cstring>
const int maxN=10000;
using namespace std;
int pre[maxN+1];
int find(int),n,m,a,b,ans=0,op;
void join(int,int);
int main()
{
    scanf("%d%d",&n,&m);
    memset(pre,0,sizeof(pre));
    for(int i=1;i<=n;i++) pre[i]=i;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&a,&b);
        if(op==1) join(a,b);
        else
            if(find(a)==find(b)) printf("Y\n");
            else printf("N\n");
    }
    return 0;
}
int find(int x)
{
    int r=x;
    while(pre[r]!=r) r=pre[r];
    while(x!=r)
    {
        int p=pre[x];
        pre[x]=r;
        x=p;
    }
    return r;
}
void join(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy) pre[fx]=fy;
}

欧拉筛素数

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=30000000,maxM=3000000;
bool flag[maxN+1];
int p[maxM+1],tot,x,y,n;
void prime(int);
int main()
{
    memset(flag,true,sizeof(flag));
    scanf("%d%d",&x,&n);
    prime(x);
    flag[1]=false;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&y);
        if(flag[y]) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}
void prime(int x)
{
    for(int i=2;i<=x;i++)
    {
        if(flag[i]) p[tot++]=i;
        for(int j=0;j<tot && i*p[j]<=x;j++)
        {
            flag[i*p[j]]=false;
            if(i%p[j]==0) break;
        }
    }
}

//小根堆
#include<iostream>
#include<cstdio>
using namespace std;
const int maxN=1000;
int n,heap_size,heap[maxN+1];
void put(int),get();
int main()
{
    heap_size=0;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int x,op;
        scanf("%d",&op);
        switch(op)
        {
            case 1:scanf("%d",&x); put(x); break;
            case 2:printf("%d\n",heap[1]); break;
            case 3:get(); break;
        }
    }
}
void put(int x)
{
    int son,pa;
    son=++heap_size;
    heap[son]=x;
    while(son>1)
    {
        pa=son>>1;
        if(heap[pa]<=heap[son]) break;
        swap(heap[pa],heap[son]);
        son=pa;
    }
}
void get()
{
    int son,pa=1;
    heap[pa]=heap[heap_size--];
    while(pa*2<=heap_size)
    {
        son=pa<<1;
        if(son<heap_size && heap[son+1]<heap[son]) son++;
        if(heap[pa]<=heap[son]) break;
        swap(heap[pa],heap[son]);
        pa=son; 
    }
}

快速幂取余运算

#include<iostream>
#include<cstdio>
using namespace std;
long long x,p,m,result,tp;
int main()
{
    scanf("%lld%lld%lld",&x,&p,&m); tp=p;
    printf("%lld^%lld mod %lld=",x,p,m);
    result=1;
    while(p)
    {
        if(p%2==1) result=result*x%m;
        p/=2; x=x*x%m;
    }
    if(tp==0) printf("%lld",1%m);
    else printf("%lld",result);
    return 0;
}

最小生成树

1、Prim

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=10000,maxM=2000000;
struct Node
{
    int from,to,next,value;
}edge[maxM+1];
int n,m,head[maxN+1],dis[maxN+1],tot=0,MST;
int fa[maxN+1];
bool flag[maxN+1];
void add_edge(int,int,int);
void prim();
int main()
{
    memset(dis,0x3f,sizeof(dis));
    memset(edge,0,sizeof(edge));
    memset(head,0,sizeof(head));
    memset(flag,true,sizeof(flag));
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
    {
        int x,y,t;
        scanf("%d%d%d",&x,&y,&t);
        add_edge(x,y,t);
        add_edge(y,x,t);
    }
    prim();
    return 0;
}
void prim()
{
    dis[1]=0; MST=0;
    for(int i=1;i<=n;i++)
    {
        int k=0;
        for(int j=1;j<=n;j++)
            if(flag[j] && dis[k]>dis[j])
                k=j;
        flag[k]=false;
        MST+=dis[k];
        //if(fa[k]) printf("%d %d\n",fa[k],k);
        for(int j=head[k];j;j=edge[j].next)
        {
            int x=edge[j].to;
            if(edge[j].value<dis[x] && flag[x])
                dis[x]=edge[j].value,fa[x]=k;
        }
    }
    if(MST) printf("%d",MST);
    else printf("orz");
}
void add_edge(int x,int y,int t)
{
    tot++;
    edge[tot].from=x;
    edge[tot].to=y;
    edge[tot].value=t;
    edge[tot].next=head[x];
    head[x]=tot;
}

2、Kruskal

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxN=5000,maxM=200000;
struct Node
{
    int from,to,value;
}edge[maxM+1];
bool comp(Node a,Node b) {return a.value<b.value;}
int kruskal(),pre[maxN+1],n,m;
int find(int); void join(int,int);
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) pre[i]=i;
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&edge[i].from,&edge[i].to,&edge[i].value);
    sort(edge+1,edge+m+1,comp);
    int temp=kruskal();
    if(temp==-1) printf("orz");
    else printf("%d",temp);
    return 0;
}
int kruskal()
{
    int MST=0,k=1;
    for(int i=1;i<=m;i++)
    {
        int u=edge[i].from;
        int v=edge[i].to;
        if(find(u)!=find(v))
        {
            join(u,v);
            //printf("%d %d\n",edge[i].from,edge[i].to);
            MST+=edge[i].value;
            k++;
        }
        if(k>=n) return MST;
    }
    return -1;
}
int find(int x)
{
    if(pre[x]!=x) pre[x]=find(pre[x]);
    return pre[x];
}
void join(int x,int y)
{
    int fx=find(x);
    int fy=find(y);
    if(fx!=fy) pre[fx]=fy;
}

差分约束

差分约束,即利用一类不等式的解建图

即给出 \(n\) 个变量和 \(m\) 个不等式,每个不等式形如 \(x[i]-x[j]\leq a[k] \ (0\leq i,j<n\ , 0\leq k<m)\),求 \(x[n-1]-x[0]\) 的最大值
线性约束(第一组:\(x\)\(y\) 距离不大于 \(w\),第二组:\(x\)\(y\) 距离不小于 \(w\) ):

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxN=10000;
struct Node
{
	int to,value,next,from;
}edge[2*maxN+5];
int head[maxN+1],dis[maxN+1],q[maxN+1];
int k,vis[maxN+1],n,m,tot=0;
bool flag[maxN+1];
void add_edge(int,int,int);
int SPFA(int);
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	for(int i=0;i<m;i++)
	{
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		add_edge(x,y,w);
	}
	for(int i=0;i<k;i++)
	{
		int x,y,w;
		scanf("%d%d%d",&x,&y,&w);
		add_edge(y,x,-w);
	}
	for(int i=2;i<=n;i++)
		add_edge(i,i-1,1);
	printf("%d",SPFA(1));
	return 0;
}
void add_edge(int x,int y,int t)
{
    tot++;
    edge[tot].from=x;
    edge[tot].to=y;
    edge[tot].value=t;
    edge[tot].next=head[x];
    head[x]=tot;
}
int SPFA(int s)
{
    int q_head=0,q_tail=0;
    q[q_tail++]=s;
    flag[s]=true;
	dis[s]=0;
    while(q_head!=q_tail)
    {
        int x=q[q_head];
        flag[x]=false;
        if(++vis[x]>n) return -1;
        for(int i=head[x];i;i=edge[i].next)
            if(dis[x]+edge[i].value<dis[edge[i].to])
            {
                dis[edge[i].to]=dis[x]+edge[i].value;
                if(!flag[edge[i].to])
                {
                    flag[edge[i].to]=true;
                    q[q_tail++]=edge[i].to;
                    if(q_tail>n) q_tail=0;
                }
            }
        q_head++;
       if(q_head>n) q_head=0;
    }
    if(dis[n]==0x3f3f3f3f) return -2;
    else return dis[n];
}
posted @ 2019-02-16 09:42  常青藤的花语  阅读(216)  评论(0编辑  收藏  举报

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。