洛谷春季 ACM 多校训练第二周
T123571 Misaka Network
这题我犯了一个逻辑错误,人傻了,想了半天也没debug出来;
做法:
是这样一个逻辑问题,一个点不是控制点,就是如果有控制点连到它就行了。
但,一个点是控制点,不是说连到它的点不是控制点就行了,只要有一个连到它的控制点,那它就不是控制点。
标准错误解法:
这个想法就是,vis=1表示他是控制点,如果一个点不是控制点,那么他的所有邻居就是控制点。
这肯定是错了,如果他的邻居有其他控制点可以连到呢?那这个邻居就不是控制点。
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; #define pb push_back bool vis[N]; int ans,in[N]; int n,m; vector<int>e[N]; void toposort(){ queue<int>Q; for(int i=1;i<=n;i++)if(in[i]==0)vis[i]=1,Q.push(i); while(!Q.empty()){ int u=Q.front();Q.pop(); if(vis[u])ans++; for(int i=0;i<e[u].size();i++){ int v=e[u][i]; if(!vis[u])vis[v]=1; if(--in[v]==0)Q.push(v); } } } int main(){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)in[i]=0,vis[i]=0; int a,b; while(m--){ scanf("%d %d",&a,&b); e[a].pb(b); in[b]++; } ans=0; toposort(); printf("%d\n",ans); return 0; }
正确解法:逻辑正确;
如果一个点是控制点,那么他的所有邻居就不是控制点。这个是正确的逻辑;】
#include<bits/stdc++.h> using namespace std; const int N=1e5+5; #define pb push_back bool vis[N]; int ans,in[N]; int n,m; vector<int>e[N]; void toposort(){ queue<int>Q; for(int i=1;i<=n;i++)if(in[i]==0)Q.push(i); while(!Q.empty()){ int u=Q.front();Q.pop(); if(!vis[u])ans++; for(int i=0;i<e[u].size();i++){ int v=e[u][i]; if(!vis[u])vis[v]=1; if(--in[v]==0)Q.push(v); } } } int main(){ scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)in[i]=0,vis[i]=0; int a,b; while(m--){ scanf("%d %d",&a,&b); e[a].pb(b); in[b]++; } ans=0; toposort(); printf("%d\n",ans); return 0; }
T123573 Schedule
中模拟:题意:给你一个课的时间,让你排一个课表,每次问你这天的课程;
做法:这题主要是不好表示,set<cla>course[N][7];表示第几周,第几天的课程;
然后插入遍历,本来想搞个优先队列,但是无法遍历,所以只能set;
#include <bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; typedef long double ldb; const int N=1e4+5; struct cla{string name;int st,et; cla(string s,int a,int b){name=s,st=a,et=b;} friend bool operator<(cla A,cla B){ return A.et<B.et; } }; bool cmp(cla A,cla B){ return A.et<B.et;} set<cla>course[N][7]; int mp[350]; int main(){ mp['o']=1,mp['u']=2,mp['e']=3,mp['h']=4,mp['r']=5; int n,q;string s;char day[10]; scanf("%d",&n); getchar(); for(int i=1;i<=n;i++){ getline(cin,s); s[s.size()-1]='\0'; int sw,ew,sl,el; while(scanf("%d-%d%s%d-%d\n",&sw,&ew,day,&sl,&el)==5){ // char tmp=days[1]; int d=mp[day[1]]; for(int w=sw;w<=ew;w++){ course[w][d].insert(cla(s,sl,el)); } } if(i==n)q=sw; } while(q--){ int w; scanf("%d %s",&w,day); int d=mp[day[1]]; set<cla>::iterator it; for(it=course[w][d].begin();it!=course[w][d].end();it++) cout<<it->st<<"-"<< it->et <<" "<<it->name<<endl; // printf("%d-%d %s\n",course[w][d][i].s,course[w][d][i].e,course[w][d][i].s); // printf("\n"); puts(""); } // system("pause"); return 0; }
T123575 Anan and Minecraft
题意:给你两个图,判断是否联通同构;
做法:看明白以后这题真的是。。。。
其实判断是否联通同构真的很简单,每次读入u,v;
用一个cnt表示两个集合的差,那么每次加入u,v的话,看看另一个集合u,v是否联通。
如果联通,cnt--,否则cnt++;
#include<bits/stdc++.h> using namespace std; #define pb push_back typedef long long ll; const int N=2e5+5; const int inf=0x3f3f3f3f; int fa1[N],fa2[N]; int find1(int x){return fa1[x]==x?x:fa1[x]=find1(fa1[x]);} int find2(int x){return fa2[x]==x?x:fa2[x]=find2(fa2[x]);} void build1(int x,int y){int dx=find1(fa1[x]),dy=find1(fa1[y]);if(dx!=dy)fa1[dx]=dy;} void build2(int x,int y){int dx=find2(fa2[x]),dy=find2(fa2[y]);if(dx!=dy)fa2[dx]=dy;} int main(){ int n,m; scanf("%d %d",&n,&m); for(int i=1;i<=n;i++)fa1[i]=fa2[i]=i; int u,v,op,cnt=0; while(m--){ scanf("%d %d %d",&op,&u,&v); if(op==1){ if(find2(u)!=find2(v))cnt--; else cnt++; build1(u,v); } else { if(find1(u)!=find1(v))cnt--; else cnt++; build2(u,v); } if(!cnt)puts("A"); else puts("B"); } return 0; }
想的太多,做的太少;