缩点(洛谷3387)——不会写DP 的我只好来了个SPFA

  我刚开始也不知道为什么就想到肯定是缩了点后把一个新点(原图中的强连通分量)的权值赋为它所含的所有点的权值之和,没有想着去推,纯粹是题目的名字启发我这么去干的……之后用SPFA 求最大路径,然而我连的全是无向边,导致答案错误了四个点,发现错误后觉得,之前的代码居然还对了六个点才是最让人震惊的。

 1 #include<queue>
 2 #include<stack>
 3 #include<vector>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<cstring>
 7 #include<cstdlib>
 8 #include<cstdio>
 9 using namespace std;
10 const int N=10111;
11 int n,m,ival[N],val[N],pre[N],low[N],dfn,col[N],cnt,dgr[N],res,f[N];
12 bool ins[N];
13 vector<int> igr[N],gr[N];
14 stack<int> s;
15 void dfs(int x){
16     pre[x]=low[x]=dfn++;
17     s.push(x);ins[x]=true;
18
19     for(int i=0;i<igr[x].size();i++)
20         if(!pre[igr[x][i]]){
21             dfs(igr[x][i]);
22             low[x]=min(low[x],low[igr[x][i]]);
23         }
24         else if(ins[igr[x][i]])low[x]=min(low[x],pre[igr[x][i]]);
25
26     if(low[x]==pre[x]){
27         cnt++;
28         int u;
29         do{
30             u=s.top();s.pop();
31             col[u]=cnt;
32             val[cnt]+=ival[u];
33             ins[u]=false;
34         }while(u!=x);
35     }
36 }
37
38 void spfa(int sx){
39     queue<int> q;
40     bool inq[N];memset(inq,0,sizeof inq);
41     q.push(sx);inq[sx]=true;
42
43     res=max(res,f[sx]=val[sx]);
44
45     while(!q.empty()){
46         int x=q.front();q.pop();inq[x]=false;
47         for(int i=0;i<gr[x].size();i++)
48             if(f[gr[x][i]]<f[x]+val[gr[x][i]]){
49                 res=max(res,f[gr[x][i]]=f[x]+val[gr[x][i]]);
50                 if(!inq[gr[x][i]])q.push(gr[x][i]);
51             }
52     }
53
54 }
55
56 int main(){
57     cin>>n>>m;
58     for(int i=1;i<=n;i++)cin>>ival[i];
59     while(m--){
60         int x,y;cin>>x>>y;
61         igr[x].push_back(y);
62     }
63
64     for(int i=1;i<=n;i++)
65         if(!pre[i])
66             dfs(i);
67
68     for(int i=1;i<=n;i++)
69         for(int j=0;j<igr[i].size();j++)
70             if(col[i]!=col[igr[i][j]]){
71                 gr[col[i]].push_back(col[igr[i][j]]);
72                 dgr[col[igr[i][j]]]++;
73             }
74
75     for(int i=1;i<=cnt;i++)
76         if(dgr[i]==0)
77             spfa(i);
78
79     cout<<res<<endl;
80     return 0;
81 }

Method_01

  洛谷 300ms

时间: 2024-11-02 17:18:20

缩点(洛谷3387)——不会写DP 的我只好来了个SPFA的相关文章

[tarjan缩点] 洛谷P2746 [USACO5.3]校园网Network of Schools

一开始完全没有搞懂题目的意思就下手,但是居然还AC了两个点? 仔细审视了一下题目的意思,发现题目并不难. 对于第一问,我们只需要求缩点后,入度为 0 的点的数量就可以了. 对于第二问,我们的目标是要求缩点后的所有点互相联通(因为只有这样,任选一个点才能互相到达)我们转换一下含义:缩点后的所有点只有入度和出度都大于0 才为互相联通所以第二问我们只需要对入度为0的点和出度0的点做个比较,谁大取谁的值输出. 坑点:需要特判一下只有一个联通块的时候,否则会出错. #include <cstdio> #

洛谷1002 容斥原理+dfs OR DP

//By SiriusRen #include <bits/stdc++.h> using namespace std; #define int long long int n,m,sx,sy,xx[]={1,1,2,2,-1,-1,-2,-2,0},yy[]={2,-2,1,-1,2,-2,1,-1,0}; int stk1[25],stk2[25],stk[25],C[45][45],Ans,top; bool check(int x,int y){return x>=0&&

洛谷 P1273 有线电视网(dp)

/* 想了半天没想出状态 自己还是太弱了 QAQ 题目问的是最多供给多少户 一般想法是把这个值定义为状态量 没想出来QAQ....看了看题解的状态 很机智.... f[i][j]表示i的子树 选了j个叶子的最大收益 这样 不亏本就是收益>=0 转移的话 先搜一下这个子树有几个叶子 然后枚举儿子 枚举当前儿子分几个叶子 这里的枚举顺序有套路 从大到小枚举i分几个 从小到大枚举j分几个 这样可以避免 重复选择 注意初始化 */ #include<iostream> #include<c

洛谷P1220关路灯[区间DP]

题目描述 某一村庄在一条路线上安装了n盏路灯,每盏灯的功率有大有小(即同一段时间内消耗的电量有多有少).老张就住在这条路中间某一路灯旁,他有一项工作就是每天早上天亮时一盏一盏地关掉这些路灯. 为了给村里节省电费,老张记录下了每盏路灯的位置和功率,他每次关灯时也都是尽快地去关,但是老张不知道怎样去关灯才能够最节省电.他每天都是在天亮时首先关掉自己所处位置的路灯,然后可以向左也可以向右去关灯.开始他以为先算一下左边路灯的总功率再算一下右边路灯的总功率,然后选择先关掉功率大的一边,再回过头来关掉另一边

洛谷P1156 垃圾陷阱[背包DP]

题目描述 卡门――农夫约翰极其珍视的一条Holsteins奶牛――已经落了到“垃圾井”中.“垃圾井”是农夫们扔垃圾的地方,它的深度为D(2<=D<=100)英尺. 卡门想把垃圾堆起来,等到堆得与井同样高时,她就能逃出井外了.另外,卡门可以通过吃一些垃圾来维持自己的生命. 每个垃圾都可以用来吃或堆放,并且堆放垃圾不用花费卡门的时间. 假设卡门预先知道了每个垃圾扔下的时间t(0< t<=1000),以及每个垃圾堆放的高度h(1<=h<=25)和吃进该垃圾能维持生命的时间f(

洛谷OJ 2051 中国象棋 DP(计数)

https://www.luogu.org/problem/show?pid=2051 题意:n*m棋盘,n,m<=100 问在棋盘上放炮 使得任意两个炮都互补攻击(即同行或者同列最多放两个)的方法数? 定义状态,dp[i][j][k] 已经放了i行 有j列放一个炮,有k列放2个炮 (并不需要准确知道当前棋盘的状态)状态转移时,按照第i行如何放炮即可 #include <bits/stdc++.h> using namespace std; typedef long long ll; c

洛谷 P1270 “访问”美术馆(树形DP)

P1270 “访问”美术馆 题目描述 经过数月的精心准备,Peer Brelstet,一个出了名的盗画者,准备开始他的下一个行动.艺术馆的结构,每条走廊要么分叉为两条走廊,要么通向一个展览室.Peer知道每个展室里藏画的数量,并且他精确测量了通过每条走廊的时间.由于经验老到,他拿下一幅画需要5秒的时间.你的任务是编一个程序,计算在警察赶来之前,他最多能偷到多少幅画. 输入输出格式 输入格式: 第1行是警察赶到的时间,以s为单位.第2行描述了艺术馆的结构,是一串非负整数,成对地出现:每一对的第一个

洛谷P1220关路灯——区间DP

题目:https://www.luogu.org/problemnew/show/P1220 区间DP. 代码如下: #include<iostream> #include<cstdio> using namespace std; int n,c,pos[55],w[55],sum,s[55][55],dp[55][55][3],INF=10000006; int main() { scanf("%d%d",&n,&c); for(int i=1

洛谷P1018乘积最大——区间DP

题目:https://www.luogu.org/problemnew/show/P1018 区间DP+高精,注意初始化和转移的细节. 代码如下: #include<iostream> #include<cstdio> #include<cstring> #define MAXN 20005 using namespace std; typedef long long ll; ll n,k,a[45],f[45][7][MAXN],tmp[MAXN],num[MAXN]