洛谷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 &lt;bits/stdc++.h&gt;#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&lt;(const node2 &amp;b) const {if (rd==b.rd) return ans&gt;b.ans; else return rd&lt;b.rd;}};priority_queue &lt;node2&gt; 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&gt;&gt;n&gt;&gt;m;    for (int i=1;i&lt;=m;i++)    {        int xx,yy; cin&gt;&gt;xx&gt;&gt;yy; build(xx,yy);        rd[yy]++;    }        for (int i=1;i&lt;=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]&lt;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&lt;=n;i++) cout&lt;&lt;ans[i]&lt;&lt;endl;    return 0;}/* 我cyq的算法为什么只值60分?    汗汗汗    whyyy?    利用贪心思想,在按照拓扑排序的顺序,(也不是拓扑排序),直接找入度为0的点。全部压入队伍。&lt;-initialize    对于每个点,如果已经被更新过了,就再找一编判断一下(其实这里可以存一个&ldquo;被影响的链&rdquo;然后把那条链上的数值全部加1;                如果没有被更新过,则找一下看看。                如果找过了却没有被更新,那就找啊?            按照入度为第一关键字升序排序,ans(也就是能够找到的点降序排序)*/</pre></div>

posted @ 2019-12-11 21:45  procaka  阅读(152)  评论(0)    收藏  举报