标签:开始 png font buffer can ring dell mat a*
T1菜肴制作:拓扑排序+大根堆
卡了好一会儿才过掉。正序拓扑的话贪心策略会出错。
保证先输出小的,倒序拓扑保证先搞大的。然后插到大根堆里。
每次取出最大的(堆顶)进行拓扑扩展。pop出来的直接扔进栈里。
多判有点恶心。记得清空(我就因为tot没清空,样例第三组单测正确,多测就错。。)
还有一个特殊判断:栈内元素个数与本身元素个数是否相符。
不相符就是剩下了环搞不出来,impossible就行了。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #define rint register int using namespace std; int T,n,m,a,b,tot,first[100003]; int du[100003]; struct node{ int u,v,nxt; }; bool pan=0,vis[100003]; inline void add(int uu,int vv,node edge[]) { ++tot; edge[tot].u=uu; edge[tot].v=vv; edge[tot].nxt=first[uu]; first[uu]=tot; } int main() { scanf("%d",&T); while(T--) { scanf("%d %d",&n,&m); memset(vis,0,sizeof(vis)); memset(du,0,sizeof(du)); memset(first,0,sizeof(first)); tot=0; priority_queue <int> q; stack <int> s; node edge[100003]; for(rint i=1;i<=m;++i) { scanf("%d %d",&a,&b); add(b,a,edge);du[a]++; } for(rint i=1;i<=n;++i) { if(!du[i])q.push(i); vis[i]=1; } if(q.empty()){cout<<"Impossible!"<<endl;continue;} while(!q.empty()) { int xx=q.top();s.push(xx);q.pop(); // cout<<xx<<endl; pan=0; for(rint i=first[xx];i;i=edge[i].nxt) { int yy=edge[i].v; du[yy]--; if(!du[yy]) { pan=1; q.push(yy); // cout<<"yy"<<yy<<endl; vis[yy]=1; } } // if(pan==0&&q.empty()){cout<<"Impossible!"<<endl;break;} } // if(pan==0)continue; if(s.size()!=n){cout<<"Impossible!"<<endl;continue;} while(!s.empty()) { cout<<s.top()<<‘ ‘; s.pop(); } cout<<endl; } }
T2矩阵游戏:二分图
锝瑟一把这题全hzoj我是第一个A掉的
二分图,一开始还真没想起来。查bzoj上这道题的时候撇了一眼看到了二分图三个字。
好的。(不要脸)但是真的忘了啊QAQ只好翻出ftp里尘封多年的二分图ppt。
手码了一遍匈牙利感觉还不错。
挺基础,行列分别建点,黑格建边,跑一边匈牙利,用黑格去匹配行和列。
然而没认真看题,人家让输出“Yes”或“No”,我输出“YES”“NO”完美w0。。。
加了一堆卡常特盘,148毫算是挺快的了吧?(wtf 102ms!收小的一拜)
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<cmath> #include<algorithm> using namespace std; const int N=205; int a[N][N]; int vis[N],matx[N],maty[N]; int tot; int n; int hun(int x) { for(int i=1;i<=n;i++) { //int y=to[i]; if(!vis[i]&&a[x][i]) { vis[i]=1; if(maty[i]==-1||hun(maty[i])) { maty[i]=x; matx[x]=i; return 1; } } } return 0; } int main(){ int T; scanf("%d",&T); while(T--){ tot=0; memset(maty,-1,sizeof(maty)); memset(matx,-1,sizeof(matx)); scanf("%d",&n); int cnt=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]); int ans=0; for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(hun(i)) ans++; } //cout<<ans<<endl; if(ans!=n){ printf("No\n"); } else puts("Yes\n"); } }
T3约会 Rendezvous:基环树
为什么基环树的题目都这么恶心还是我太弱鸡了?
我可能卡了一年。自己想出来的代码5.0k,198行……我真的没勇气调下去了。
记录了一大堆东西。判断的语句写了一堆。。真的是堆QAQ。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<vector> #define rint register int const int L=1<<20|1; char buffer[L],*S,*T; #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++) using namespace std; int n,m,head[500005],tot,fat[500005]; int dex,cnt,t,bar[500005],bl[500005],ac[500005]; int d[500005],f[500005][20],l_a[500005],l_b[500005]; vector<int>dell[500005];queue<int>q; struct node{int to,nxt;}edge[500005]; int read() { rint a=0,b=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)b=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){a=a*10+ch-‘0‘;ch=getchar();} return a*b; } void add(rint x,rint y) { edge[++tot].to=y; edge[tot].nxt=head[x]; head[x]=tot; } int find(rint x) { if(fat[x]==x) return x; return fat[x]=find(fat[x]); } void get_dell(rint x,rint dex) { bar[x]=dex; for(rint i=head[x];i;i=edge[i].nxt) { rint y=edge[i].to; if(bar[y]==dex) { ++cnt; while(y!=x) { dell[cnt].push_back(x); x=ac[x]; } dell[cnt].push_back(y); } else ac[y]=x,get_dell(y,dex); } } void bfs(rint x,rint tp) { d[x]=1,bl[x]=tp; q.push(x); while(!q.empty()) { rint x=q.front(); q.pop(); for(rint i=head[x];i;i=edge[i].nxt) { rint y=edge[i].to; if(!bar[y]&&!d[y]) { bl[y]=tp;d[y]=d[x]+1; q.push(y);f[y][0]=x; for(rint j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1]; } } } } int Lca(rint x,rint y) { if(d[x]>d[y]) swap(x,y); for(rint i=t;i>=0;i--) if(d[f[y][i]]>=d[x]) y=f[y][i]; if(x==y) return x; for(rint i=t;i>=0;i--) { if(f[y][i]^f[x][i]) { y=f[y][i]; x=f[x][i]; } } return f[x][0]; } void solve() { for(rint i=1;i<=n;i++) if(!bar[i]) get_dell(i,++dex); memset(bar,0,sizeof(bar)); for(rint i=1;i<=cnt;i++) for(rint j=0;j<dell[i].size();j++) bar[dell[i][j]]=1,l_a[dell[i][j]]=j,l_b[dell[i][j]]=i; for(rint i=1;i<=cnt;i++) for(rint j=0;j<dell[i].size();j++) bfs(dell[i][j],dell[i][j]); } int main() { n=read(),m=read(); t=log2(n)+1; for(rint i=1;i<=n;i++) fat[i]=i; for(rint i=1,x;i<=n;i++) { x=read(); add(x,i); fat[find(i)]=find(x); } solve(); for(rint i=1,x,y;i<=m;i++) { x=read(),y=read(); if(find(x)!=find(y)) printf("-1 -1\n"); else if(bl[x]==bl[y]) { rint lca=Lca(x,y); rint ll=d[x]-d[lca],rr=d[y]-d[lca]; printf("%d %d\n",ll,rr); } else { rint ll=abs(l_a[bl[x]]-l_a[bl[y]]),rr=dell[l_b[bl[x]]].size()-ll; rint edge=d[x]-d[bl[x]],r=d[y]-d[bl[y]]; rint ans1,ans2,ans3,ans4; if(l_a[bl[x]]<l_a[bl[y]]) ans1=edge+ll,ans2=r,ans3=edge,ans4=r+rr; else ans1=edge+rr,ans2=r,ans3=edge,ans4=r+ll; if(max(ans1,ans2)<max(ans3,ans4)) printf("%d %d\n",ans1,ans2); else if(max(ans1,ans2)>max(ans3,ans4)) printf("%d %d\n",ans3,ans4); else { if(min(ans1,ans2)<min(ans3,ans4)) printf("%d %d\n",ans1,ans2); else if(min(ans1,ans2)>min(ans3,ans4)) printf("%d %d\n",ans3,ans4); else printf("%d %d\n",max(ans1,ans2),min(ans1,ans2)); } } } return 0; }
T4tree:最小生成树+二分答案
被天皇忽悠说这道题贼恶心,去看题解(推锅推锅)然后1A掉不想说话。
不是特别好想。不过填了一种最小生成树题目的做题方法:通过改变边权来改变最小生成树的构成。
黑白边,要求need条白边。一开始sb的想成了树里只有白边。
显然还有n-1-need条黑边 /糊脸(n是节点数目)顺嘴吐槽:BZOJ上直接跑最小生成树都能过……
二分给白边加上边权,跑kruskal最小生成树,看是否符合need条白边。
直接暴力累计就好了没必要开优化(懒)还有人直接爆搜不二分都A了……
<-这是爆搜
<-这是二分
建议打二分咕咕咕~
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<stack> #include<algorithm> #define rint register int using namespace std; int n,m,need,l,r,cnt,tot,ans; int u[100005],v[100005],c[100005],col[100005]; int fa[100005]; struct node {int u,v,c,col;}edge[100005]; inline int read() { int a=0,b=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)b=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){a=(a<<3)+(a<<1)+(ch-‘0‘);ch=getchar();} return a*b; } inline bool cmp(node a,node b){return a.c==b.c?a.col<b.col:a.c<b.c;} inline int get(int x){return x==fa[x]?x:fa[x]=get(fa[x]);} inline bool kruskal(int x) { int f1,f2,sum=0; for(rint i=1;i<=n;i++) fa[i]=i; for(rint i=1;i<=m;i++) { edge[i].u=u[i]; edge[i].v=v[i]; edge[i].c=c[i]; edge[i].col=col[i]; if(!col[i]) edge[i].c+=x; } sort(edge+1,edge+m+1,cmp); for(rint i=1;i<=m;i++) { f1=get(edge[i].u),f2=get(edge[i].v); if(f1!=f2) { fa[f1]=f2; sum++; tot+=edge[i].c; if(!edge[i].col) cnt++; } if(sum==n-1) if(cnt>=need)return 1; else return 0; } } int main() { n=read(),m=read(),need=read(); for(rint i=1;i<=m;i++) u[i]=read()+1,v[i]=read()+1,c[i]=read(),col[i]=read(); l=-101,r=101; while(l<r) { tot=cnt=0; int mid=(l+r)>>1; if(kruskal(mid)) l=mid+1,ans=tot-need*mid; else r=mid; } cout<<ans<<endl; return 0; }
T5太鼓达人:dfs欧拉回路
颓了题解,膜拜soul神佬。
一看题真的想不出来哪里和图论有关系……查了一下全说打表……
坑
标签:开始 png font buffer can ring dell mat a*
原文地址:https://www.cnblogs.com/xingmi-weiyouni/p/11180135.html