UVA - 11324 The Largest Clique

本文详细介绍了如何通过强连通分量分析、缩点、构造scc图并求最长路径来解决寻找图中节点数目最多的强连通分量的问题。包括spfa算法的应用和邻接矩阵与邻接表的使用比较。

给定一个图,求一个节点数目最多的团,对于其中任意两个节点u,v至少存在一条这样的路径使得u到v,或者v到u。

分析: 先求出强连通分量,然后缩点,构成一个scc图,然后求一条最长的路,每个节点的权重即为该强连通分量的节点数目,由于是DAG, 所以可以用dp或者spfa,一开始用记忆化搜索竟然TLE,想也想不通,后来改成spfa,以0为起点,然后求出距离0的最大距离。

spfa:

  1 #include <iostream>
  2 #include <sstream>
  3 #include <cstdio>
  4 #include <climits>
  5 #include <cstring>
  6 #include <cstdlib>
  7 #include <string>
  8 #include <stack>
  9 #include <map>
 10 #include <cmath>
 11 #include <vector>
 12 #include <queue>
 13 #include <algorithm>
 14 #define esp 1e-6
 15 #define pi acos(-1.0)
 16 #define pb push_back
 17 #define mp(a, b) make_pair((a), (b))
 18 #define in  freopen("in.txt", "r", stdin);
 19 #define out freopen("out.txt", "w", stdout);
 20 #define print(a) printf("%d\n",(a));
 21 #define bug puts("********))))))");
 22 #define stop  system("pause");
 23 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++)
 24 
 25 #define inf 0x0f0f0f0f
 26 
 27 using namespace std;
 28 typedef long long  LL;
 29 typedef vector<int> VI;
 30 typedef pair<int, int> pii;
 31 typedef vector<pii,int> VII;
 32 typedef vector<int>:: iterator IT;
 33 const int maxn = 5000;
 34 int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
 35 int a[maxn], dp[maxn], dis[maxn], inq[maxn];
 36 VI g[maxn], G[maxn];
 37 stack<int> S;
 38 void dfs(int u)
 39 {
 40     S.push(u);
 41     lowlink[u] = pre[u] = ++dfs_clock;
 42     for(int i = 0; i < g[u].size(); i++)
 43     {
 44         int  v = g[u][i];
 45         if(!pre[v])
 46         {
 47             dfs(v);
 48             lowlink[u] = min(lowlink[u], lowlink[v]);
 49         }
 50         else if(!sccno[v])
 51         {
 52             lowlink[u] = min(lowlink[u], pre[v]);
 53         }
 54     }
 55     int cnt= 0;
 56     if(lowlink[u] == pre[u])
 57     {
 58         scc_cnt++;
 59         for(;;)
 60         {
 61             int x = S.top();
 62             S.pop();
 63             cnt++;
 64             sccno[x] = scc_cnt;
 65             if(x ==  u)
 66             {
 67                 a[scc_cnt] = cnt;
 68                 break;
 69             }
 70         }
 71     }
 72 }
 73 void find_scc(int n)
 74 {
 75     memset(pre, 0, sizeof(pre));
 76     memset(sccno, 0, sizeof(sccno));
 77 
 78     dfs_clock = scc_cnt = 0;
 79     for(int i = 0; i < n; i++)
 80         if(!pre[i]) dfs(i);
 81 }
 82 void spfa(void)
 83 {
 84     memset(inq, 0, sizeof(inq));
 85     memset(dis, 0, sizeof(dis));
 86     queue<int> q;
 87     inq[0] = 1;
 88     q.push(0);
 89     while(!q.empty())
 90     {
 91         int u = q.front();
 92         q.pop();
 93         inq[u] = 0;
 94         for(int i = 0; i < G[u].size(); i++)
 95         {
 96             int v = G[u][i];
 97             if(dis[v] < dis[u] + a[v])
 98                 if(dis[v] = dis[u] + a[v], !inq[v])
 99                     inq[v] = 1, q.push(v);
100         }
101     }
102 }
103 int main(void)
104 {
105     int n, m;
106     int T;
107     for(int t = scanf("%d", &T); t <= T; t++)
108     {
109         for(int i = 0; i < maxn; i++)
110             g[i].clear(), G[i].clear();
111         scanf("%d%d", &n, &m);
112         memset(a, 0, sizeof(a));
113         while(m--)
114         {
115             int u, v;
116             scanf("%d%d", &u, &v);
117             u--, v--;
118             g[u].pb(v);
119         }
120         find_scc(n);
121         for(int u = 0; u < n; u++)
122             for(int i = 0; i < g[u].size(); i++)
123             {
124                 int v = g[u][i];
125                 if(sccno[v] != sccno[u])
126                     G[sccno[u]].pb(sccno[v]);
127             }
128         for(int i = 1; i <= scc_cnt; i++)
129             G[0].pb(i);
130         spfa();
131         int ans = 0;
132         for(int i = 1; i <= scc_cnt; i++)
133             ans = max(ans, dis[i]);
134         printf("%d\n", ans);
135     }
136     return 0;
137 }
View Code

下面是dp代码,一开始用的邻接矩阵存储关系图,后来改成邻接表果断过了,以后要注意了,尽量用邻接表

  1 #include <iostream>
  2 #include <sstream>
  3 #include <cstdio>
  4 #include <climits>
  5 #include <cstring>
  6 #include <cstdlib>
  7 #include <string>
  8 #include <stack>
  9 #include <map>
 10 #include <cmath>
 11 #include <vector>
 12 #include <queue>
 13 #include <algorithm>
 14 #define esp 1e-6
 15 #define pi acos(-1.0)
 16 #define pb push_back
 17 #define mp(a, b) make_pair((a), (b))
 18 #define in  freopen("in.txt", "r", stdin);
 19 #define out freopen("out.txt", "w", stdout);
 20 #define print(a) printf("%d\n",(a));
 21 #define bug puts("********))))))");
 22 #define stop  system("pause");
 23 #define Rep(i, c) for(__typeof(c.end()) i = c.begin(); i != c.end(); i++)
 24 
 25 #define inf 0x0f0f0f0f
 26 
 27 using namespace std;
 28 typedef long long  LL;
 29 typedef vector<int> VI;
 30 typedef pair<int, int> pii;
 31 typedef vector<pii,int> VII;
 32 typedef vector<int>:: iterator IT;
 33 const int maxn = 5000;
 34 int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt;
 35 int a[maxn], dp[maxn], dis[maxn], inq[maxn];
 36 VI g[maxn], G[maxn];
 37 stack<int> S;
 38 void dfs(int u)
 39 {
 40     S.push(u);
 41     lowlink[u] = pre[u] = ++dfs_clock;
 42     for(int i = 0; i < g[u].size(); i++)
 43     {
 44         int  v = g[u][i];
 45         if(!pre[v])
 46         {
 47             dfs(v);
 48             lowlink[u] = min(lowlink[u], lowlink[v]);
 49         }
 50         else if(!sccno[v])
 51         {
 52             lowlink[u] = min(lowlink[u], pre[v]);
 53         }
 54     }
 55     int cnt= 0;
 56     if(lowlink[u] == pre[u])
 57     {
 58         scc_cnt++;
 59         for(;;)
 60         {
 61             int x = S.top();
 62             S.pop();
 63             cnt++;
 64             sccno[x] = scc_cnt;
 65             if(x ==  u)
 66             {
 67                 a[scc_cnt] = cnt;
 68                 break;
 69             }
 70         }
 71     }
 72 }
 73 void find_scc(int n)
 74 {
 75     memset(pre, 0, sizeof(pre));
 76     memset(sccno, 0, sizeof(sccno));
 77 
 78     dfs_clock = scc_cnt = 0;
 79     for(int i = 0; i < n; i++)
 80         if(!pre[i]) dfs(i);
 81 }
 82 void spfa(void)
 83 {
 84     memset(inq, 0, sizeof(inq));
 85     memset(dis, 0, sizeof(dis));
 86     queue<int> q;
 87     inq[0] = 1;
 88     q.push(0);
 89     while(!q.empty())
 90     {
 91         int u = q.front();
 92         q.pop();
 93         inq[u] = 0;
 94         for(int i = 0; i < G[u].size(); i++)
 95         {
 96             int v = G[u][i];
 97             if(dis[v] < dis[u] + a[v])
 98                 if(dis[v] = dis[u] + a[v], !inq[v])
 99                     inq[v] = 1, q.push(v);
100         }
101     }
102 }
103 int main(void)
104 {
105     int n, m;
106     int T;
107     for(int t = scanf("%d", &T); t <= T; t++)
108     {
109         for(int i = 0; i < maxn; i++)
110             g[i].clear(), G[i].clear();
111         scanf("%d%d", &n, &m);
112         memset(a, 0, sizeof(a));
113         while(m--)
114         {
115             int u, v;
116             scanf("%d%d", &u, &v);
117             u--, v--;
118             g[u].pb(v);
119         }
120         find_scc(n);
121         for(int u = 0; u < n; u++)
122             for(int i = 0; i < g[u].size(); i++)
123             {
124                 int v = g[u][i];
125                 if(sccno[v] != sccno[u])
126                     G[sccno[u]].pb(sccno[v]);
127             }
128         for(int i = 1; i <= scc_cnt; i++)
129             G[0].pb(i);
130         spfa();
131         int ans = 0;
132         for(int i = 1; i <= scc_cnt; i++)
133             ans = max(ans, dis[i]);
134         printf("%d\n", ans);
135     }
136     return 0;
137 }
View Code

 

基于数据驱动的 Koopman 算子的递归神经网络模型线性化,用于纳米定位系统的预测控制研究(Matlab代码实现)内容概要:本文围绕“基于数据驱动的Koopman算子的递归神经网络模型线性化”展开,旨在研究纳米定位系统的预测控制方法。通过结合数据驱动技术与Koopman算子理论,将非线性系统动态近似为高维线性系统,进而利用递归神经网络(RNN)建模并实现系统行为的精确预测。文中详细阐述了模型构建流程、线性化策略及在预测控制中的集成应用,并提供了完整的Matlab代码实现,便于科研人员复现实验、优化算法并拓展至其他精密控制系统。该方法有效提升了纳米级定位系统的控制精度与动态响应性能。; 适合人群:具备自动控制、机器学习或信号处理背景,熟悉Matlab编程,从事精密仪器控制、智能制造或先进控制算法研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①实现非线性动态系统的数据驱动线性化建模;②提升纳米定位平台的轨迹跟踪与预测控制性能;③为高精度控制系统提供可复现的Koopman-RNN融合解决方案; 阅读建议:建议结合Matlab代码逐段理解算法实现细节,重点关注Koopman观测矩阵构造、RNN训练流程与模型预测控制器(MPC)的集成方式,鼓励在实际硬件平台上验证并调整参数以适应具体应用场景。
### k-clique 的概念及其在社交网络中的应用 在一个无向图 \( G=(V,E) \) 中,如果存在一个子图使得其中任意两个不同的顶点都由一条边直接相连,则此子图称为完全图或者团 (clique)[^1]。当这个完全图恰好有 \( k \) 个节点时,就称之为 \( k \)-clique 或者 \( k \)-团。 对于社交网络而言,\( k \)-clique 可以用来表示一组高度互联的朋友群组,在这样的群组里每个人都是其他人的朋友或者是彼此间的关系非常密切。寻找这些紧密联系的小团体有助于深入理解社会关系网内部结构特征,并可用于多种实际应用场景之中,比如推荐新朋友、预测信息扩散路径等。 #### 寻找最大 \( k \)-clique 的基本思路 为了有效地找出所有的 \( k \)-cliques,可以采用递归的方式遍历整个图形: - **初始化阶段**:设定初始参数,包括待探索的最小团大小 \( k_{min} \),以及当前正在考察的最大已知团尺寸 \( max\_size \)。 - **剪枝操作**:利用一些先验条件提前终止不必要的搜索分支,减少计算量。例如,若某节点剩余邻居数目不足以构成新的更大团,则可以直接跳过对该节点进一步深挖的可能性。 - **回溯过程**:从单个起点出发逐步扩大候选集合直到满足预设阈值为止;一旦发现符合条件的新团即记录下来并尝试继续延伸至更高阶数;如果不成功则返回至上一状态重新选取不同方向前进。 具体到实现层面,KClist++ 提出了基于 Frank-Wolfe 算法框架来优化这一流程,它能够动态调整各定点的重要性评分从而指导后续的选择决策,不过其缺点在于每次迭代都要重做一次完整的枚举工作,导致整体耗时较长[^3]。 另一方面,针对传统方法中存在的效率瓶颈问题——特别是那些依赖于频繁执行最大流运算或是反复求解所有可能存在的 \( k \)-Clique 的方案——研究者们也在不断探索更加高效的替代途径,旨在降低算法复杂度的同时提升处理速度和适用范围[^4]。 ```python def find_k_cliques(graph, k): cliques = [] def extend_candidates(current_set, candidates): nonlocal graph if len(current_set) >= k: is_complete = all((u,v) in graph.edges or (v,u) in graph.edges for u in current_set for v in current_set if u != v) if is_complete and sorted(list(current_set)) not in map(sorted, cliques): cliques.append(set(current_set)) elif candidates: candidate_node = next(iter(candidates)) neighbors_of_candidate = set([n for n in graph.neighbors(candidate_node)]) new_candidates_with_node = candidates.intersection(neighbors_of_candidate) extend_candidates(current_set | {candidate_node}, new_candidates_with_node) new_candidates_without_node = candidates.difference({candidate_node}) extend_candidates(current_set, new_candidates_without_node) nodes = list(graph.nodes()) while nodes: node_to_start = nodes.pop() initial_neighbors = set(graph.neighbors(node_to_start)) extend_candidates({node_to_start}, initial_neighbors) return cliques ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值