【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划

10分算法:对于城市网络为一条单向链的数据,

20分算法:对于n<=20的数据,暴力搜出所有的可能路径。 结合以上可以得到30分。

60分算法:分析题意可得使者会带着去的城市也就是这个城市所在强联通分量的其他城市,这个过程的代价也就是这个强联通分量的城市数-1,且他可以选择任何一个其中的城市离开这个强联通分量。于是我们求出所有强联通分量,记录下每一个包含的城市数,然后缩点。接下来再用dfs,由于数据是构造的,只能得到60分。

100分算法:在缩点之后,这个图变成了一个有向无环图,我们将一条边连向的SCC包含的城市数看做边权(<--其实一条边的边权是一个pair,pair.first为其连向的SCC包含的城市数;pair.second为原本的边权+其连向的SCC包含的城市数-1,这样问题就转化为了求一个有向无环图上的最长路径,利用DP或者Spfa或者其他的方法求解即可,本题没有构造卡Spfa的数据。

比赛的时候写的缩点+暴搜,被卡成60分。

//下划线为官方题解。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 #define M 500001
 7 #define N 100001
 8 struct Node
 9 {
10     int v,w;
11     Node(const int &a,const int &b){v=a;w=b;}
12     Node(){}
13 };
14 struct Edge
15 {
16     int u,v,w;
17     Edge(const int &a,const int &b,const int &c){u=a;v=b;w=c;}
18     Edge(){}
19 }edges[M];
20 vector<Node>ljb[M];
21 vector<int>vs,G[M],rG[M];
22 typedef vector<int>::iterator ITER;
23 typedef vector<Node>::iterator Edge_ITER;
24 int sum,n,m,x,y,z,anscity,cnt[N],cmp[N],anscost=2147483647;
25 bool vis[N];
26 void dfs(int U)
27 {
28     vis[U]=1;
29     for(ITER it=G[U].begin();it!=G[U].end();it++)
30       if(!vis[*it])
31         dfs(*it);
32     vs.push_back(U);
33 }
34 void rdfs(int U)
35 {
36     vis[U]=1;
37     cmp[U]=sum;
38     cnt[sum]++;
39     for(ITER it=rG[U].begin();it!=rG[U].end();it++)
40       if(!vis[*it])
41         rdfs(*it);
42 }
43 void scc()
44 {
45     for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);
46     memset(vis,0,sizeof(vis));
47     ITER it=vs.end(); it--;
48     for(;;it--)
49       {
50           if(!vis[*it])
51           {
52               sum++;
53               rdfs(*it);
54           }
55           if(it==vs.begin()) break;
56       }
57 }
58 void dfs3(int U,int city,int cost)
59 {
60     if(city>anscity)
61       {
62           anscity=city;
63           anscost=cost;
64       }
65     else if(city==anscity && cost<anscost)
66       anscost=cost;
67     for(Edge_ITER it=ljb[U].begin();it!=ljb[U].end();it++)
68       dfs3((*it).v,city+cnt[(*it).v],cost+(*it).w+cnt[(*it).v]-1);
69 }
70 int main()
71 {
72     scanf("%d%d",&n,&m);
73     for(int i=1;i<=m;i++)
74       {
75           scanf("%d%d%d",&x,&y,&z);
76           G[x].push_back(y);
77           rG[y].push_back(x);
78           edges[i]=Edge(x,y,z);
79       }
80     scc();
81     for(int i=1;i<=m;i++)
82       if(cmp[edges[i].u]!=cmp[edges[i].v])
83         ljb[cmp[edges[i].u]].push_back(Node(cmp[edges[i].v],edges[i].w));
84     dfs3(cmp[1],cnt[cmp[1]],cnt[cmp[1]]-1);
85     printf("%d %d\n",anscity,anscost);
86     return 0;
87 }

后来写的缩点+spfa,要注意所谓的spfa最长路是双关键字比较的,优先让pair.first最大化,再让pair.second最小化,重载下运算符就可以了。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<algorithm>
  5 #include<queue>
  6 using namespace std;
  7 #define INF 2147483647
  8 #define M 500001
  9 #define N 100001
 10 queue<int>q;
 11 struct Node
 12 {
 13     int v,w;
 14     Node(const int &a,const int &b){v=a;w=b;}
 15     Node(){}
 16 }dis[N];
 17 bool operator < (const Node &a,const Node &b)
 18 {return a.v!=b.v ? a.v<b.v : a.w>b.w;}
 19 Node operator + (const Node &a,const Node &b)
 20 {return Node(a.v+b.v,a.w+b.w);}
 21 struct Edge
 22 {
 23     int u,v,w;
 24     Edge(const int &a,const int &b,const int &c){u=a;v=b;w=c;}
 25     Edge(){}
 26 }edges[M];
 27 vector<Edge>ljb[M];
 28 vector<int>vs,G[M],rG[M];
 29 typedef vector<int>::iterator ITER;
 30 typedef vector<Edge>::iterator Edge_ITER;
 31 int sum,n,m,x,y,z,anscity,cnt[N],cmp[N],anscost=2147483647;
 32 Node ans;
 33 bool vis[N],inq[N];
 34 void dfs(int U)
 35 {
 36     vis[U]=1;
 37     for(ITER it=G[U].begin();it!=G[U].end();it++)
 38       if(!vis[*it]) dfs(*it);
 39     vs.push_back(U);
 40 }
 41 void rdfs(int U)
 42 {
 43     vis[U]=1; cmp[U]=sum; cnt[sum]++;
 44     for(ITER it=rG[U].begin();it!=rG[U].end();it++)
 45       if(!vis[*it]) rdfs(*it);
 46 }
 47 void scc()
 48 {
 49     for(int i=1;i<=n;i++) if(!vis[i]) dfs(i);
 50     memset(vis,0,sizeof(vis));
 51     ITER it=vs.end(); it--;
 52     for(;;it--)
 53       {
 54           if(!vis[*it])
 55           {
 56               sum++;
 57               rdfs(*it);
 58           }
 59           if(it==vs.begin()) break;
 60       }
 61 }
 62 void spfa(const int &s)//Node.v权最大化的城市数,Node.w权为最小化的cost
 63 {
 64     for(int i=2;i<=sum;i++) dis[i]=Node(-INF,INF);
 65     dis[1]=Node(cnt[s],cnt[s]-1);
 66     inq[1]=1; ans=Node(-2147483647,2147483647);
 67     q.push(1);
 68     while(!q.empty())
 69       {
 70         int cur=q.front();
 71         for(Edge_ITER it=ljb[cur].begin();it!=ljb[cur].end();it++)
 72           if(dis[(*it).u]<dis[cur]+Node((*it).v,(*it).w))
 73             {
 74             dis[(*it).u]=dis[cur]+Node((*it).v,(*it).w);
 75             if(!inq[(*it).u])
 76               {
 77                 q.push((*it).u);
 78                 inq[(*it).u]=1;
 79               }
 80             }
 81         q.pop(); inq[cur]=0;
 82       }
 83     for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
 84     printf("%d %d\n",ans.v,ans.w);
 85 }
 86 int main()
 87 {
 88     scanf("%d%d",&n,&m);
 89     for(int i=1;i<=m;i++)
 90       {
 91           scanf("%d%d%d",&x,&y,&z);
 92           G[x].push_back(y);
 93           rG[y].push_back(x);
 94           edges[i]=Edge(x,y,z);
 95       }
 96     scc();
 97     for(int i=1;i<=m;i++)
 98       if(cmp[edges[i].u]!=cmp[edges[i].v])
 99         ljb[cmp[edges[i].u]].push_back(Edge(cmp[edges[i].v],cnt[cmp[edges[i].v]],edges[i].w+cnt[cmp[edges[i].v]]-1));
100     spfa(1);
101     return 0;
102 }
时间: 2024-10-10 17:16:01

【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划的相关文章

ZOJ 3795 Grouping(强联通分量 + 缩点 + Dp)

Problem Description: Suppose there are N people in ZJU, whose ages are unknown. We have some messages about them. The i-th message shows that the age of person si is not smaller than the age of person ti. Now we need to divide all these N people into

【POJ1236】Network of Schools 强联通分量缩点(本文kosaraju)

/*不要说这题多水之类的--我只是想记一下kosaraju这种屌炸天的dfs序延伸算法(说不定能加到我的ygylca里面)*/ 题意神马的都不说了,好吧,就是给你个图,n个点,然后n行每行都描述该点的出边,图建完了,然后缩点,然后问多少个点没有入度,再问需要加几条边可以让图变强联通图. 强联通图:图中任意两点之间都能互相到达(前提得是有向图你懂的,无向图就有点乱了,根本不要算法了,暴搜就好了) 强联通分量:同强联通图,不过是图中一部分. 缩点,把一个分量视为一个点,缩起来(一般不缩,都是记录每个

hihoCoder#1185 : 连通性&#183;三 tarjan求强联通分量 缩点 dfs/拓扑排序求路径和最大值

题目链接: http://hihocoder.com/problemset/problem/1185# 题意: n个点,每个点有一个权值,m条有向边,从1出发,每走到一个点, 就吃掉这个点的草,当没有可以到达的草场或是能够到达的草场都已经被吃光了之后就要返回到1了.求最多可以吃掉多少草. 思路: 提示里面讲的挺好的 如果草场是一个强连通图,那么我们只要走到任意一点,就可以把其他所有的草场都走一遍,并且可以选择任意一个点作为终点.所以把强联通块缩成一个点 因为一个强连通块会被缩成一个点,那么我们可

【最小割】【Dinic】【强联通分量缩点】bzoj1797 [Ahoi2009]Mincut 最小割

结论: 满足条件一:当一条边的起点和终点不在 残量网络的 一个强联通分量中.且满流. 满足条件二:当一条边的起点和终点分别在 S 和 T 的强联通分量中.且满流.. 网上题解很多的. 1 #include<cstdio> 2 #include<cstring> 3 #include<vector> 4 #include<algorithm> 5 #include<queue> 6 using namespace std; 7 #define IN

【强联通分量缩点】【最短路】【spfa】bzoj1179 [Apio2009]Atm

缩点后转化成 DAG图上的单源最长路问题.spfa/dp随便. 1 #include<cstdio> 2 #include<queue> 3 #include<algorithm> 4 #include<vector> 5 #include<cstring> 6 using namespace std; 7 int cmp[500001],sum,n,m,Us[500001],Vs[500001],t,w[500001],sta,k,ans,di

【强联通分量缩点】【搜索】bzoj2208 [Jsoi2010]连通数

两次dfs缩点,然后n次dfs暴搜. 1 #include<cstdio> 2 #include<vector> 3 #include<cstring> 4 using namespace std; 5 #define N 2001 6 vector<int>G[N],rG[N],vs,G2[N]; 7 typedef vector<int>::iterator ITER; 8 char s[N+1][N+1]; 9 int cmp[N],sum

Light OJ 1034 - Hit the Light Switches(强联通分量)

题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1034 题目大意:有n盏灯,有m个关系, 关系a,b表示如果a灯开关打开那么b灯也会亮起来, 现在求至少需要打开多少开关使所有灯都亮. 题目思路:先由强联通分量缩点, 得到DAG图, 然后根据DAG图,求出有多少入度为0的点, 即为所求. 代码如下: #include<bits/stdc++.h> using namespace std; const int N = 1000

codevs 2822 爱在心中 tarjan(强联通分量)

2822 爱在心中 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题目描述 Description “每个人都拥有一个梦,即使彼此不相同,能够与你分享,无论失败成功都会感动.爱因为在心中,平凡而不平庸,世界就像迷宫,却又让我们此刻相逢Our Home.” 在爱的国度里有N个人,在他们的心中都有着一个爱的名单,上面记载着他所爱的人(不会出现自爱的情况).爱是具有传递性的,即如果A爱B,B爱C,则A也爱C.如果有这样一部分人,他们彼此都相爱,则他们就超越了一

51nod 1076 2条不相交的路径 无向图强联通分量 trajan算法

1076 2条不相交的路径 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题  收藏  关注 给出一个无向图G的顶点V和边E.进行Q次查询,查询从G的某个顶点V[s]到另一个顶点V[t],是否存在2条不相交的路径.(两条路径不经过相同的边) (注,无向图中不存在重边,也就是说确定起点和终点,他们之间最多只有1条路) Input 第1行:2个数M N,中间用空格分开,M是顶点的数量,N是边的数量.(2 <= M <= 25000, 1 <= N <=