图论错题集1

已见过知识点:

链式前向星,floyed,dij,spfa,prim,kruscal,拓扑排序,强连通分量,差分约束,johnson全源最短路,次短路,二分图最大匹配、最小点覆盖,割点和桥,最大流,lca,rmq,st表,树上倍增,kruscal重构树

见过的技巧:

反向建图,黑白染色,点权转边权,加平台点,权值01化,边化点(kruscal重构树),反向bfs,拆点

踩过的坑:

nmd,给我仔细看好每个数组应该开多大!!!

写lca的时候数组尽量多开一点,不然会寄,而且开得多跑得还快了(

写return 0;

init写最外面

别写endl,这玩意慢得要死,以后都#define endl '\n'

待补知识点:

树链剖分,树分治,k短路,双连通,圆方树,最小费用最大流

题目列表:

[P2419 USACO08JAN]Cow Contest S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P6154 游走 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

[P1948 USACO08JAN]Telephone Lines S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1491 集合位置 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

Problem - 1385E - Codeforces

Problem - 1651D - Codeforces

Problem - E - Codeforces

https://ac.nowcoder.com/acm/problem/51269

Problem - 1245D - Codeforces

Problem - 832D - Codeforces

https://loj.ac/p/136

[P2419 USACO08JAN]Cow Contest S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

虽然只是一个黄题,但是我没见过这种做法,所以记一下(我本来是在刷拓扑排序,不知道怎么突然冒出来一个这个题)

题意:一张代表能力强弱关系的有向图,问最多能确定多少人的排名。

思路:我本来写的反向建图拓扑排序,发现不对,因为找不到什么好的结论去推答案,然后翻了翻题解,就没人写拓扑排序,用的floyed判任意两点之间的连通性,想想也是,毕竟N才100。

 #include <bits/stdc++.h>
 using namespace std;
 int mp[101][101];
 int main(){
     int n,m;
     cin>>n>>m;
     for(int i=0;i<m;i++){
         int a,b;
         cin>>a>>b;
         mp[a][b]=1;
     }
     for(int k=1;k<=n;k++){
         for(int i=1;i<=n;i++){
             for(int j=1;j<=n;j++){
                 mp[i][j]|=(mp[i][k]&&mp[k][j]);
             }
         }
     }
     int ans=0;
     for(int i=1;i<=n;i++){
         int tes=1;
         for(int j=1;j<=n;j++){
             if(i==j){
                 continue;
             }
             if((mp[i][j]|mp[j][i])==0){
                 tes=0;
                 break;
             }
         }
         if(tes==1){
             ans++;
         }
     }
     cout<<ans<<endl;
     return 0;
 }

P6154 游走 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

拓扑排序+dp+期望,看完题解觉得不过如此,md怎么就没做出来呢?

题意:一张有向无环图,计算所有路径的长度期望

思路:我本来想的是记录下到达每个点分别有哪些长度的点,每个长度对应几条边,但是t了,因为我没有必要知道具体的每条边的长度,我需要知道的是总长度和总路径数,因为都是等概率的,所以其实只要记录下到每个点路径总长度和总条数即可

 #include <bits/stdc++.h>
 using namespace std;
 #define int long long
 #define ll long long
 const int mod=998244353;
 ll quick_pow(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
 ll inv(ll x) {return quick_pow(x, mod-2);}
 void read(int &x){
     int f=1;x=0;char s=getchar();
     while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
     while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
     x*=f;
 }
 struct node{
     int ne,to,val;
 };
 node edge[700001];
 int head[100001];
 int cnt=0;
 void addedge(int a,int b){
     edge[cnt].ne=head[a];
     edge[cnt].to=b;
     head[a]=cnt++;
 }
 int ru[100001];
 int num[100001];
 int dis[100001];
 int n,m;
 int sum=0;
 int cn=0;
 void tuopu(){
     queue<int>q;
     for(int i=1;i<=n;i++){
         if(ru[i]==0){
             q.push(i);
         }
         num[i]=1;
     }
     while(!q.empty()){
         int t=q.front();
         q.pop();
         //cout<<t<<endl;
         for(int i=head[t];i!=-1;i=edge[i].ne){
             int son=edge[i].to;
             ru[son]--;
             num[son]+=num[t];
             num[son]%=mod;
             //这个地方想了一会:因为dis[t]存的是到t的总路径长度,想要从t走到son,每一条以t为终点的路径都需要经过edge[i]这条边,从而导致长度+1,因此这里要加上num[t]
             dis[son]+=dis[t]+num[t];
             dis[son]%=mod;
             if(ru[son]==0){
                 q.push(son);
             }
         }
     }
     for(int i=1;i<=n;i++){
         sum+=dis[i];
         sum%=mod;
         cn+=num[i];
         cn%=mod;
     }
 }
 signed main(){
     memset(head,-1,sizeof(head));
     read(n);
     read(m);
     for(int i=0;i<m;i++){
         int a,b;
         read(a);
         read(b);
         addedge(a,b);
         ru[b]++; 
     }
     tuopu();
     //cout<<sum<<" "<<cn<<endl;
     cout<<sum*inv(cn)%mod<<endl;
     return 0;
 }

[P1948 USACO08JAN]Telephone Lines S - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

题意:求原点1到n的所有路中的第k+1长的路最小值。

思路:二分应该不难想到,我们去二分这个第k+1长的路的长度,但关键是如何根据这个长度去计算是否可行&#

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wuhudaduizhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值