此题做法多啊
带权并查集,区间dp,前缀和,差分约束
1.自己写的前缀和, 11
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; const int N=105; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} int T,n,m,l,r,v,sum,s[N]; int main(){ T=read(); while(T--){ int fg=1; n=read();m=read(); rep(i,1,m){ l=read();r=read();v=read(); sum=s[r]-s[l-1]; if(sum==0) s[r]=s[l-1]+v; else if(sum&&sum!=v){printf("false\n");fg=0;break;}} if(fg) printf("true\n"); }return 0; }
2.自己写的区间dp
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} const int N=105; int T,n,m,x,y,z,p,f[N][N]; int main(){ T=read(); while(T--){ n=read();m=read(); rep(i,1,m){ x=read();y=read();z=read(); f[x][y]=z;} p=1; for(int i=1;i<n;i++)if(p) for(int j=i+1;j<=n;j++)if(p) for(int k=i;k<j;k++)if(p) if(f[i][k]&&f[k+1][j]) if(f[i][j]&&f[i][j]!=f[i][k]+f[k+1][j]){ p=0;break;} else f[i][j]=f[i][k]+f[k][j]; if(p==0) printf("false\n"); else printf("true\n"); }return 0; }
3.区间dp 100
注意枚举时的方向,此题第二层为逆序(没有明白啊啊啊)
#include<bits/stdc++.h> using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} const int N=105; int f[N][N],w,n,m,p,s,t,v; int main(){ w=read(); while(w--){ memset(f,0,sizeof(f)); n=read(),m=read(); for(int i=1;i<=m;i++){ s=read(),t=read(),v=read(); f[s][t]=v;} p=1; for(int i=2;i<=n;i++)if(p) for(int j=i-1;j>=1;j--)if(p) for(int k=j;k<i;k++) if(f[j][k]&&f[k+1][i]){ if(f[j][i]&&f[j][i]!=f[j][k]+f[k+1][i]) {p=0;break;} else f[j][i]=f[j][k]+f[k+1][i];} if(p==0) printf("false\n"); else printf("true\n"); } return 0; }
4.带权并查集
Attention!!!!!
f,ff提前取出来,不明原因,惨痛的教训。。。问提交满了一整页是怎样的感受
#include<bits/stdc++.h> #define rep(i,x,y) for(register int i=x;i<=y;i++) #define dec(i,x,y) for(register int i=x;i>=y;i--) #define int long long using namespace std; const int N=1050; inline int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f;} int T,n,m,x,y,z,fg,xx,yy,fa[N],cha[N]; int find(int x){ if(fa[x]==x) return x; int f=fa[x],ff=find(fa[x]);cha[x]+=cha[f]; //先推直接父亲权值,再路径压缩 fa[x]=ff;return ff; } signed main(){ T=read(); while(T--){ fg=1;n=read();m=read(); rep(i,0,n) fa[i]=i,cha[i]=0; rep(i,1,m){ x=read();y=read();z=read();x--; xx=find(x),yy=find(y); if(xx!=yy){ fa[yy]=xx,cha[yy]=cha[x]+z-cha[y];} //此处 y连接在x 的子树上,y的深度大 else if(cha[y]-cha[x]!=z) fg=0; }if(fg) printf("true\n");else printf("false\n"); } }
5.差分约束+spfa判断(实在不想写这道题了啊啊啊)
#include <cstdio> #include <vector> using namespace std; const int maxn = 105; const int maxm = 1005; struct node{ int to, val; }; vector<node> e[maxn]; int t, n, m, dis[maxn]; bool vis[maxn], flag; void SPFA(int x){ \\其实就是 DFS vis[x] = 1; for(int i = 0; i < e[x].size(); i++){ node v = e[x][i]; if(dis[v.to] > dis[x] + v.val){ if(vis[v.to]){flag = 1; return;} dis[v.to] = dis[x] + v.val; SPFA(v.to); } } vis[x] = 0; return; } int main(){ scanf("%d", &t); while(t--){ scanf("%d%d", &n, &m); for(int i = 1; i <= m; i++){ int u, v, w; scanf("%d%d%d", &u, &v, &w); e[u-1].push_back((node){v, w}); e[v].push_back((node){u-1, -1*w}); //建图 } for(int i = 0; i <= n; i++){ dis[i] = 0; SPFA(i); if(flag) { break;} } if(flag) printf("false\n"); else printf("true\n"); for(int i = 0; i <= n; i++){ \\记得在判断完每一组之后复位 vis[i] = 0; dis[i] = 0; e[i].clear(); } flag = 0; } return 0; }