拓扑图最长路 等于 背包问题求方案数
因为要求点不同 存在多条边同一情况 需要边判重(set)
拓扑求方案数
#include <iostream> #include <cstring> #include <algorithm> #include <unordered_set> using namespace std; typedef long long LL; const int N = 1e5+10,M=2e6+10; int n,m,mod; int h[N],hs[N], e[M], ne[M], idx;//hs表头2 int dfn[N],low[N],timestamp; int stk[N],top; bool in_stk[N]; int id[N],scc_cnt,Size[N]; int f[N],g[N];//f是点数 g方案数 void add(int h[],int a, int b) //给那个表头建立边 添加一条边a->b { e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ; } void tarjan(int u){ dfn[u]=low[u]=++timestamp; stk[++top]=u,in_stk[u]=true; for (int i = h[u]; ~i ; i =ne[i] ){ int j=e[i]; if(!dfn[j]){ tarjan(j); low[u]=min(low[u],low[j]); }else if(in_stk[j]){ low[u]=min(low[u],dfn[j]); } } if(dfn[u]==low[u]){ ++scc_cnt; int y; do{ y=stk[top--]; in_stk[y]=false; id[y]=scc_cnt; Size[scc_cnt]++; }while(u!=y); } } int main() { memset(h, -1, sizeof h); memset(hs, -1, sizeof hs); cin>>n>>m>>mod; while (m -- ){ int a,b; cin >> a>>b; add(h, a, b); } for (int i = 1; i <= n; i ++ ){ if(!dfn[i]) tarjan(i); } //这里需要建新图 unordered_set<LL>s;//(U,V) -> u*10000+v for(int i=1;i<=n;i++){ for (int j = h[i]; ~j ; j=ne[j]){ int k=e[j]; int a=id[i],b=id[k]; LL hash= a*1000000LL +b; if(a!=b && !s.count(hash)){//如果边之前没加过 add(hs,a, b);//加上这条边 s.insert(hash); } } } //scc 节点编号递减的顺序就是 top序 for (int i = scc_cnt; i ; i -- ){ if(!f[i]){//没有更新过就是起点 f[i]=Size[i]; g[i]=1; } for(int j=hs[i];~j;j=ne[j]){ int k=e[j]; if(f[k]<f[i]+Size[k]){ f[k]=f[i]+Size[k]; g[k]=g[i]; }else if(f[k]==f[i]+Size[k]){ g[k]=(g[k]+g[i])%mod; } } } int maxf=0,sum=0;//sum方案数 maxf最大值 for (int i = 1; i <= scc_cnt; i ++ ){ if(f[i]>maxf){ maxf=f[i]; sum=g[i]; } else if(f[i]==maxf) sum=(sum+g[i])%mod; } cout << maxf<<endl; cout << sum<<endl; return 0; }