洛谷p1137 旅行计划 图论-拓扑排序
2019/12/24
题解:乍一看以为是松弛的板子题,结果是拓扑排序的板子题
通过拓扑排序维护剩余点集,如果这个点(叫他点v吧)还有入度,证明v一定有从“另外一条边(u,v)上”走进来的更优解,因为,令“另外一条边“的起始点u,此时要么入度为0,要么还没进队呢”。~~~~~~~~~~~~~~1
又因为是bfs,所以一个深度的bfs的答案永远是所遍历到的点的最优解。~~~~~~~~~~~~~~~~`2
假设深度为d,那么v点虽然被连接到了,理应是d+1,但因为还存在入度,也就是一定存在另外一条路径a->b->c----->v而路径的起点a点此时的深度也为d+1.所以明显从a点走到v点比较优~~~~~~~~~~~~~~2
故就去搞a点了。
应该算贪心。
下面是AC代码
#include <bits/stdc++.h>#define MAXN 100010#define MAXM 200010usingnamespacestd;
int rd[MAXN],vis[MAXN],head[MAXN],ans[MAXN],temp[MAXN],cont,n,m;
struct node{int v,next;}edge[MAXM];
queue <int> q;
int cnt=0;
void build(int u,int v)
{cnt++; edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt;}
int main()
{
cin>>n>>m;
for (int i=1;i<=m;i++)
{
int xx,yy; cin>>xx>>yy; build(xx,yy);
rd[yy]++;
}
for (int i=1;i<=n;i++)
if (!rd[i]) q.push(i);
while (!q.empty())
{
int tmp2=q.front(); q.pop();
for (int i=head[tmp2];i;i=edge[i].next)
{
rd[edge[i].v]--; ans[edge[i].v]=max(ans[edge[i].v],ans[tmp2]+1);
if (rd[edge[i].v]==0) {q.push(edge[i].v);}
}
}
for (int i=1;i<=n;i++) cout<<ans[i]+1<<endl;
return0;
}
//这是六十分时的吐槽
/* 我cyq的算法为什么只值60分?
汗汗汗
whyyy?
利用贪心思想,在按照拓扑排序的顺序,(也不是拓扑排序),直接找入度为0的点。全部压入队伍。<-initialize
对于每个点,如果已经被更新过了,就再找一编判断一下(其实这里可以存一个“被影响的链”然后把那条链上的数值全部加1;
如果没有被更新过,则找一下看看。
如果找过了却没有被更新,那就找啊?
按照入度为第一关键字升序排序,ans(也就是能够找到的点降序排序)
果然要queue来搞。
*/
<div class="cnblogs_Highlighter"><pre class="brush:cpp;gutter:true;">#include <bits/stdc++.h>#define MAXN 100010#define MAXM 200010using namespace std;int rd[MAXN],vis[MAXN],head[MAXN],ans[MAXN],temp[MAXN],cont,n,m;struct node{int v,next;}edge[MAXM];struct node2{int x,rd,ans;bool operator<(const node2 &b) const {if (rd==b.rd) return ans>b.ans; else return rd<b.rd;}};priority_queue <node2> q;
int cnt=0;void build(int u,int v){cnt++; edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt;}
int main(){ cin>>n>>m; for (int i=1;i<=m;i++) { int xx,yy; cin>>xx>>yy; build(xx,yy); rd[yy]++; } for (int i=1;i<=n;i++) if (!rd[i]) {node2 tmp; tmp.x=i; tmp.rd=0; tmp.ans=1; q.push(tmp);}
while (!q.empty()) { node2 tmp; tmp=q.top(); q.pop(); if (ans[tmp.x]<tmp.ans) {ans[tmp.x]=tmp.ans; vis[tmp.x]=0;} if (vis[tmp.x]==1) continue; vis[tmp.x]=1; for (int i=head[tmp.x];i;i=edge[i].next) { node2 tmp2; tmp2.x=edge[i].v; tmp2.rd=rd[tmp2.x]-1; rd[tmp2.x]--; tmp2.ans=tmp.ans+1; q.push(tmp2); } } for (int i=1;i<=n;i++) cout<<ans[i]<<endl; return 0;}/* 我cyq的算法为什么只值60分? 汗汗汗 whyyy? 利用贪心思想,在按照拓扑排序的顺序,(也不是拓扑排序),直接找入度为0的点。全部压入队伍。<-initialize 对于每个点,如果已经被更新过了,就再找一编判断一下(其实这里可以存一个“被影响的链”然后把那条链上的数值全部加1; 如果没有被更新过,则找一下看看。 如果找过了却没有被更新,那就找啊? 按照入度为第一关键字升序排序,ans(也就是能够找到的点降序排序)*/</pre></div>