1.P4017 最大食物链计数
确实比较板子,但是考验思维,我愿称之为思维拓扑排序
作为拓扑的第一题,确实没想到要进行思维处理
这里考虑用一种dp的思维方式(?
多引入两个变量,一个记录出度,一个记录每一个点的种类数量,这样就可以一直满足不同方向过来所产生的种类数量
出度的缘由是这里需要绝对的两端(我开始以为是大于二的食物链都行,那样的话就每一次操作都+1就好)
贴代码(不要忘记取模,不然只有两个点捏)
// Problem:
// P4017 最大食物链计数
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P4017
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int N=5010;
vector<int> e[N];
int ans;
int din[N];//入度
int oin[N];//出度
int n,m;
int f[N];//每个点的数量void toposort(){queue<int> q;for(int i=1;i<=n;++i){if(din[i]==0) q.push(i),f[i]=1;} while(q.size()){auto k=q.front();q.pop();for(auto t:e[k]){if(--din[t]==0) q.push(t);f[t]=(f[k]+f[t])%80112002;}}for(int i=1;i<=n;++i){if(oin[i]==0) ans=(f[i]+ans)%80112002;}
}int main(){cin>>n>>m;while(m--){int a,b;cin>>a>>b;e[a].push_back(b);++din[b];++oin[a];} toposort();cout<<ans%80112002<<endl;return 0;
}
2.P2712 摄像头
这道题比较板子,在操作的时候,如果pop就ans--即可,有几个坑点
输出yes 摄像头的范围 摄像头所能照到的位置不一定会存在摄像头(怎么会有题卡这种鬼地方)
// Problem:
// P2712 摄像头
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2712
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int N=505;
vector<int> e[N];
int ans=0;
int din[N];
bool check[N];
vector<int> kkk(N);void toposort(){queue<int> q;for(int i=1;i<=ans;++i){if(din[kkk[i]]==0) q.push(kkk[i]);}while(q.size()){auto t=q.front();q.pop();//cout<<t<<endl;//cout<<ans<<endl;//cout<<endl;if(check[t]) ans--;for(auto x:e[t]){if(--din[x]==0) q.push(x);}}
}int main(){int n;cin>>n;ans=n;int cnt=0;while(n--){int a,b;cin>>a>>b;if(!check[a]) kkk[++cnt]=a,check[a]=true;while(b--){int k;cin>>k;e[a].push_back(k);din[k]++;}}toposort();if(ans==0) cout<<"YES"<<endl;else cout<<ans<<endl;return 0;
}
3.P1137 旅行计划
这道题比上一道题要简单不少,与第一题思路相同,但这一题的想法就是维护一个max就好了,我其实没有太看懂提,但是这么操作不管有几个起始点,都可以获得最大的值(看来自各个方向哪个大就选哪个方向)
// Problem:
// P1137 旅行计划
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1137
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include<iostream>
#include<queue>
#include<vector>
using namespace std;
const int N=1e5+10;
vector<int> e[N];
int din[N];
int f[N];
int n,m;void toposort(){queue<int> q;for(int i=1;i<=n;++i){if(din[i]==0) q.push(i);f[i]=1;}while(q.size()){auto t=q.front();q.pop();for(auto x:e[t]){if(--din[x]==0) q.push(x);f[x]=max(f[t]+1,f[x]);}}
}
int main(){cin>>n>>m;while(m--){int a,b;cin>>a>>b;e[a].push_back(b);din[b]++;}toposort();for(int i=1;i<=n;++i) cout<<f[i]<<endl;return 0;
}
4.P1960 郁闷的记者
这道题难过的令人无语,调试了一整天才发现是读错题了。这题面真的阴间.......
我的想法是开两个堆分别维护最大字典序和最小字典序,如果答案不同说明有不同情况(极端情况)
贴代码
// Problem:
// P1960 郁闷的记者
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1960
// Memory Limit: 500 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include<iostream>
#include<vector>
#include<queue>
using namespace std;
const int N=1e4+10;
int cnt1[N];//记录名次
int cnt2[N];
int n,m;
vector<int> e[N];
int din1[N];
int din2[N];void toposort(){priority_queue<int> a;priority_queue<int,vector<int>,greater<int>> b;for(int i=1;i<=n;++i){//cout<<din1[i]<<endl;if(din1[i]==0){a.push(i);b.push(i);//cout<<i<<endl;}}int now=0;while(a.size()){auto t=a.top();a.pop();cnt1[t]=++now;//cout<<t<<endl;//cout<<t<<endl;for(auto x:e[t]){if(--din1[x]==0) a.push(x);}}now=0;while(b.size()){auto t=b.top();b.pop();cnt2[t]=++now;cout<<t<<endl;for(auto x:e[t]){if(--din2[x]==0) b.push(x);}}
}int main(){cin>>n>>m;while(m--){int a,b;cin>>a>>b;e[a].push_back(b);din1[b]++;din2[b]++;}toposort();//for(int i=1;i<=n;++i) cout<<cnt2[i]<<endl;for(int i=1;i<=n;++i){if(cnt1[i]!=cnt2[i]){cout<<1<<endl;return 0;}}cout<<0<<endl;return 0;
}
5.P6145 [USACO20FEB] Timeline G
一遍就AC,想的时间也是最短的。
但是这道题确实比较难想,要是没跟我说这是拓扑排序我不一定能想到。这道题比较隐晦,我的思路是一个类似dp的操作(每一次都更新最大),也就是每一次都要更新到最大。
这里使用拓扑排序的原因,我总结为:每一个的结局时间都是不确定的,要先确定前面的才能确定后面的,这个过程就是一个拓扑序。
在这个拓扑序遍历的时候,对每一次进行更新(对某个点有影响的所有点(已经没有入度了)继续更新),语言无力,请看代码。(我没看懂题解区说的递推是啥)
// Problem:
// P6145 [USACO20FEB] Timeline G
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P6145
// Memory Limit: 256 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int n,m,s;
const int N=1e5+10;
int f[N];
vector<pair<int,int>> e[N];
int din[N];void toposort(){queue<int> q;for(int i=1;i<=n;++i){if(din[i]==0) q.push(i);}while(q.size()){auto t=q.front();q.pop();for(auto x:e[t]){int a=x.first,b=x.second;f[a]=max(f[a],f[t]+b);//每次都更新一下if(--din[a]==0) q.push(a);}}
}int main(){cin>>n>>m>>s;for(int i=1;i<=n;++i) cin>>f[i];while(s--){int a,b,c;cin>>a>>b>>c;e[a].push_back({b,c});din[b]++;}toposort();for(int i=1;i<=n;++i) cout<<f[i]<<endl;return 0;
}
6.P1807 最长路
这道题有点坑,有不少遭点,一开始我以为可以直接copy上一题代码(还是太想去睡觉了),结果发现必须是从1到n的路径。
这里有几个坑点
1.从1到n 且题目已经告诉你路径一定是从小节点到大节点的,枉我想了这么久的环
2.这里的权值可以是负数,所以应该把2-n的所有编程-1e9
3.由于指定了起始位置,还会存留一下入度为0的值,对后面的数字造成不良影响,对此,我们可以把这些先一步捞出来处理一下就好,见代码
好像是dp的方法吧,话说感觉越来越板了,拓扑都是这样的题目,每道题都要结合一点dp思想来着
上代码
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int n,m,s;
const int N=2000;
const int M=5e4+10;//数据不要开错了
int f[N];
vector<pair<int,int>> e[M];
int din[N];
bool check;void toposort(){queue<int> q;for(int i=2;i<=n;++i){if(din[i]==0) q.push(i);f[i]=-1e9;}while(q.size()){//多一个处理,减少这些不会入队的值对入队的影响auto t=q.front();q.pop();for(auto x:e[t]){int a=x.first;if(--din[a]==0) q.push(a);}}q.push(1);while(q.size()){auto t=q.front();q.pop();if(t==n) check=true;for(auto x:e[t]){int a=x.first,b=x.second;f[a]=max(f[a],f[t]+b);if(--din[a]==0) q.push(a);}}
}int main(){cin>>n>>m;while(m--){int a,b,c;cin>>a>>b>>c;e[a].push_back({b,c});din[b]++;}toposort();if(check) cout<<f[n]<<endl;else cout<<-1<<endl;return 0;
}
7.P1113 杂务
这道题小细节比较多,我调试了一个钟,但是思路与前面又很大的相似之处,其实好像又是dp思想,难度不大,直接贴代码
// Problem:
// P1113 杂务
//
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1113
// Memory Limit: 125 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)#include<iostream>
#include<vector>
#include<queue>
using namespace std;
int n;
const int N=1e4+10;
int din[N];
int f[N];
int now[N];
vector<int> e[N];
int ans=0;void toposort(){queue<int> q;for(int i=1;i<=n;++i){if(din[i]==0) q.push(i);}while(q.size()){auto t=q.front();q.pop();ans=max(ans,now[t]);for(auto x:e[t]){now[x]=max(now[x],now[t]+f[x]);//cout<<now[x]<<endl;//cout<<1<<endl;if(--din[x]==0) q.push(x);}}
}int main(){cin>>n;for(int i=1;i<=n;++i){cin>>i;int k;cin>>f[i];now[i]=f[i];while(cin>>k){if(k==0) break;else{e[k].push_back(i);din[i]++;//cout<<i<<' '<<din[i]<<endl;}}}//for(int i=1;i<=n;++i) cout<<din[i]<<endl;toposort();cout<<ans<<endl;return 0;
}