hdu4496 D-City

D-City

Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 0 Accepted Submission(s): 0


Problem Description
Luxer is a really bad guy. He destroys everything he met. One day Luxer went to D-city. D-city has N D-points and M D-lines. Each D-line connects exactly two D-points. Luxer will destroy all the D-lines. The mayor of D-city wants to know how many connected blocks of D-city left after Luxer destroying the first K D-lines in the input. Two points are in the same connected blocks if and only if they connect to each other directly or indirectly.

Input
First line of the input contains two integers N and M. Then following M lines each containing 2 space-separated integers u and v, which denotes an D-line. Constraints: 0 < N <= 10000 0 < M <= 100000 0 <= u, v < N.

Output
Output M lines, the ith line is the answer after deleting the first i edges in the input.

Sample Input
5 10 0 1 1 2 1 3 1 4 0 2 2 3 0 4 0 3 3 4 2 4

Sample Output
1 1 1 2 2 2 2 3 4 5
Hint
The graph given in sample input is a complete graph, that each pair of vertex has an edge connecting them, so there's only 1 connected block at first. The first 3 lines of output are 1s because after deleting the first 3 edges of the graph, all vertexes still connected together. But after deleting the first 4 edges of the graph, vertex 1 will be disconnected with other vertex, and it became an independent connected block. Continue deleting edges the disconnected blocks increased and finally it will became the number of vertex, so the last output should always be N.
反向并查集就可以了!
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
#define MAXN 10050
int father[MAXN],ans[MAXN];
struct edge{
    int s,e;
}l[100005];
int find(int x)
{
    if(father[x]!=x)
    father[x]=find(father[x]);
    return father[x];
}
int main()
{
   int n,i,m,all;
   while(scanf("%d%d",&n,&m)!=EOF)
   {
       all=n;
       for(i=0;i<=n;i++)
       {
           father[i]=i;
       }
       for(i=m-1;i>=0;i--)
       {
           scanf("%d%d",&l[i].s,&l[i].e);
       }
       for(i=0;i<m;i++)
       {
           int a=find(l[i].s);
           int b=find(l[i].e);
           if(a!=b)
           {
               father[a]=b;
               all--;
           }
           ans[i]=all;
       }
      // ans[1]=n;
       for(i=m-2;i>=0;i--)
       {
           printf("%d\n",ans[i]);
       }
       printf("%d\n",n);
   }
    return 0;
}

### HDU 1443 约瑟夫问题解析 #### 题目描述 题目涉及的是经典的约瑟夫环问题的一个变种。给定一个整数 \( k \),表示有 \( k \) 个好人和 \( k \) 个坏人,总共 \( 2k \) 个人围成一圈。编号从 1 到 \( 2k \),其中前 \( k \) 个为好人,后 \( k \) 个为坏人。目标是在不杀死任何好人的前提下,找到可以先消灭所有坏人的最小步数 \( n \)[^5]。 #### 解题思路 为了确保在杀掉第一个好人之前能将所有的坏人都清除,可以通过模拟约瑟夫环的过程来寻找符合条件的最小步数 \( n \)。一种有效的方法是利用动态规划的思想逐步缩小范围直到找到最优解。对于较大的 \( k \),由于数值较大可能导致计算复杂度增加,因此需要考虑算法效率并进行适当优化[^1]。 #### Python 实现代码 下面提供了一个基于Python编写的解决方案: ```python def josephus(k): m = 2 * k def find_min_n(m, start=1): for n in range(1, m + 1): pos = (start + n - 2) % m + 1 if all((pos - i) % m > k or (pos - i) % m == 0 for i in range(n)): return n raise ValueError("No solution found") min_n = None for good_start in range(1, k + 1): try: current_min = find_min_n(m=m, start=good_start) if not min_n or current_min < min_n: min_n = current_min except ValueError as e: continue return min_n if __name__ == "__main__": test_cases = [int(input()) for _ in range(int(input()))] results = [] for case in test_cases: result = josephus(case) print(result) ``` 此段代码实现了上述提到的逻辑,并且能够处理多个测试案例。需要注意的是,在实际应用中可能还需要进一步调整参数以及边界条件以适应不同情况下的需求[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值