暴力搜索 + 剪枝

A clique is a complete graph, in which there is an edge between every pair of the vertices. Given a graph with NNN vertices and MMM edges, your task is to count the number of cliques with a specific size SSS in the graph.

Input

The first line is the number of test cases. For each test case, the first line contains 333 integers N,MN,MN,M and SSS (N≤100,M≤1000,2≤S≤10)(N \le 100,M \le 1000,2 \le S \le 10)(N100,M1000,2S10), each of the following MMM lines contains 222 integers uuu and vvv (1≤u<v≤N)(1 \le u < v \le N)(1u<vN), which means there is an edge between vertices uuu and vvv. It is guaranteed that the maximum degree of the vertices is no larger than 202020.

Output

For each test case, output the number of cliques with size SSS in the graph.

样例输入
3
4 3 2
1 2
2 3
3 4
5 9 3
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
6 15 4
1 2
1 3
1 4
1 5
1 6
2 3
2 4
2 5
2 6
3 4
3 5
3 6
4 5
4 6
5 6
样例输出
3
7
15

题意 : 给你一张图,询问这个图中有多少个大小为 s 的完全子图
思路分析 : 因为数据比较小,因此我们直接暴力去找就可以了,对于选出的任意一个子图,只需要判断任意两条边是否都有边即可, 但是只是单纯的这样操作会超时,因为寻找了很多无用的状态,例如 1, 3, 5
大小为 3 的完全图,我们再寻找的过程中 1, 5, 3也会被找到,其实本质上是同一个完全子图,这里我们只需要在建边的时候优化一下就可以了,建的时候我们只建立单向的边,即从小到大的方向上面建边
代码示例 :

int n, m, k;
vector<int>ve[105];
int mp[105][105];
int f[105];
int ans = 0;
int vis[105];
struct edg
{
    int to, next;    
}edge[1005];
int head[1005];
int cnt = 1;

void addedge(int u, int v){
    edge[cnt].next = head[u];    
    edge[cnt].to = v;
    head[u] = cnt++;
}

void dfs(int x, int fa, int cnt){
    int sign = 0;
    for(int i = 1; i < cnt; i++){
        if (mp[x][f[i]] == 0) {sign = 1; break;}
    }    
    if (sign) return;
    f[cnt] = x; 
    
    if (cnt == k) {ans++; return;}
    for(int i = head[x]; i != -1; i = edge[i].next){
        int to = edge[i].to;
        if (to == fa) continue;
        int sign = 0;
        if (!vis[to]) { 
            vis[to] = 1;
            dfs(to, x, cnt+1);
            vis[to] = 0;
        }
    }
}

int main() { 
    int t;
    int a, b;
    
    cin >> t;
    while(t--){
        scanf("%d%d%d", &n, &m, &k);
        memset(mp, 0, sizeof(mp));
        memset(vis, 0, sizeof(vis));
        
        memset(head, -1, sizeof(head));
        cnt = 1;
        for(int i = 1; i <= m; i++){
            scanf("%d%d", &a, &b);
            if (a > b) swap(a, b);
            addedge(a, b);
            mp[a][b] = mp[b][a] = 1;            
        }
        ans = 0;
        for(int i = 1; i <= n; i++){
            dfs(i, 0, 1); 
        }
        printf("%d\n", ans);
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/ccut-ry/p/9756946.html

### 关于暴搜加最优化剪枝算法解决吃奶酪问题 在处理像“吃奶酪”这样的问题时,暴力搜索(Brute Force Search)是一种直观的方法,但往往由于其巨大的时间复杂度而不适合大规模输入。为了提高效率,在暴力搜索的基础上引入剪枝技术是非常必要的。 #### 暴力搜索剪枝策略 暴力搜索意味着尝试所有可能的情况直到找到解为止。然而,对于某些特定条件下的分支路径可以直接排除掉,这就是所谓的剪枝操作[^1]。具体到“吃奶酪”的场景下: - **距离评估**:计算当前节点到达目标位置的距离作为启发函数的一部分,当发现剩余可走步数不足以覆盖该距离,则提前终止此路线探索。 - **重复状态检测**:记录已经访问过的坐标点及其对应的状态信息;一旦遇到相同情况立即停止深入以免陷入循环或冗余运算之中。 ```python from collections import deque def bfs_with_pruning(start, end, grid): queue = deque([(start, 0)]) visited = set([start]) while queue: (x, y), dist = queue.popleft() # Prune based on distance estimation if abs(x - end[0]) + abs(y - end[1]) > remaining_steps: continue if (x, y) == end: return True directions = [(0,-1),(0,1),(-1,0),(1,0)] for dx, dy in directions: nx, ny = x + dx, y + dy if not is_valid(nx, ny, grid): continue next_state = (nx, ny) # Avoid revisiting states if next_state not in visited: visited.add(next_state) queue.append(((nx,ny),dist+1)) return False def is_valid(x,y,grid): rows, cols = len(grid),len(grid[0]) return 0<=x<rows and 0<=y<cols and grid[x][y]!='#' ``` 上述代码展示了如何利用广度优先搜索配合简单的剪枝逻辑来解决问题框架。实际应用中还需要考虑更多细节以及更复杂的约束条件来进行进一步优化[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值