1013. Battle Over Cities (25) DisjointSet & DFS 我的解法并不优雅

1013. Battle Over Cities (25)

时间限制
400 ms
内存限制
65536 kB
代码长度限制
16000 B
判题程序
Standard
作者
CHEN, Yue

It is vitally important to have all the cities connected by highways in a war. If a city is occupied by the enemy, all the highways from/toward that city are closed. We must know immediately if we need to repair any other highways to keep the rest of the cities connected. Given the map of cities which have all the remaining highways marked, you are supposed to tell the number of highways need to be repaired, quickly.

For example, if we have 3 cities and 2 highways connecting city1-city2 and city1-city3. Then if city1 is occupied by the enemy, we must have 1 highway repaired, that is the highway city2-city3.

Input

Each input file contains one test case. Each case starts with a line containing 3 numbers N (<1000), M and K, which are the total number of cities, the number of remaining highways, and the number of cities to be checked, respectively. Then M lines follow, each describes a highway by 2 integers, which are the numbers of the cities the highway connects. The cities are numbered from 1 to N. Finally there is a line containing K numbers, which represent the cities we concern.

Output

For each of the K cities, output in a line the number of highways need to be repaired if that city is lost.

Sample Input
3 2 3
1 2
1 3
1 2 3
Sample Output
1
0
0
      题目大意抽象一下就是给你一个无向图,然后删除一个点,请问为了保持整个图的连通性,至少再添加几条边。
      一开始的确想到了并查集,然后使用并查集的话对于每次询问,都需要重新初始化并建立一个并查集,这真的让我很不能忍受,真的很讨厌这种笨笨的做法,摸了一个割点算法进去,居然过了,但事实证明算法是错的,PAT的数据太水了,最后还是用了并查集。写完之后觉得再也不能当优雅的程序员了。读者有更高明的手法的话望不吝赐教。
      然后既然只考虑连通性,那就不用考虑准确地存储图,保存每条边,并的时候不考虑某一端点为删除点的边即可。
      然后,这道题目用dfs也是可以过得,为了比较,同样晒一下代码和运行结果,值得一提的是如果并查集不用路径压缩,是不能过的,比DFS还慢,真是难以理解。
# include <cstdio>
# include <cstring>
# include <algorithm>
using namespace std;

const int debug = 1;
const int _size = 1000+5;
class DisjointSet
{
private:
    int *T,size,sum;
    int FindRoot(int i){return T[i] < 0 ? i : (T[i] = FindRoot(T[i]));}
public:
    DisjointSet(int _size):size(_size)
    {
        T = new int[size];
        Init();
    }
    void Init(){sum = size;memset(T,-1,sizeof(int)*size);}
    bool Unioned(int i,int j){return FindRoot(i)==FindRoot(j);}
    void Union(int i,int j)
      {
        if ( (i = FindRoot(i) ) != ( j = FindRoot(j) ) )
        {
            T[i] = T[i] + T[j];
            T[j] = i;
            sum--;
        }
      }
    int FindSum(int i){return -T[FindRoot(i)];}
    int SumOfUnits(){return sum;}
    ~DisjointSet(){delete[] T;}
};

typedef pair <int ,int > edge;

edge e[_size*_size];

int main()
{
    int i,j,tmp;
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for (i=0;i<m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        e[i] = edge(a-1,b-1);
    } 
    while (k--)
    {
        DisjointSet U(n);
        scanf("%d",&tmp);
        for (i=0;i<m;i++)
          {
            if (e[i].first!=tmp-1&&e[i].second!=tmp-1)
                U.Union(e[i].first,e[i].second);
          }
        j = U.SumOfUnits();
        printf("%d\n",j<=2?0:j-2);
    }
    return 0;
}

#include<iostream>
#include<string.h>
#include<string>
using namespace std;

struct node
{
	int to;
	int next;
}Edge[10000000];
int N,cnt,head[1001];
bool vis[1001];
void AddEdge(int u,int v)
{
	Edge[cnt].to=v;
	Edge[cnt].next=head[u];
	head[u]=cnt++;
	Edge[cnt].to=u;
	Edge[cnt].next=head[v];
	head[v]=cnt++;
}
void DFS(int u)
{
	int i,v;
	for(i=head[u];i!=-1;i=Edge[i].next)
	{
		v=Edge[i].to;
		if(!vis[v])
		{
			vis[v]=true;
			DFS(v);
		}
	}
}
int main()
{
	int M,K,i,j;
	int a,b;
	while(cin>>N>>M>>K)
	{
		memset(head,-1,sizeof(head));
		cnt=0;
		for(i=0;i<M;++i)
		{
			cin>>a>>b;
			AddEdge(a,b);
		}
		for(i=0;i<K;++i)
		{
			cin>>a;
			memset(vis,0,sizeof(vis));
			vis[a]=true;
			cnt=0;
			for(j=1;j<=N;++j)
			{
				if(!vis[j])
				{
					DFS(j);
					cnt++;
				}
			}
			cout<<cnt-1<<endl;
		}
	}
	return 0;
}


最后是那个比并查集还快,但实际上是错的解法,不建议你看,只是为了提醒我自己
# include <cstdio>
# include <cstring>
# include <iostream>
# include <set>
using namespace std;

# define _size (1000+5)

int min(int a,int b)
{
    return a>b?b:a;
}
int n,m,k;
struct edge
{
    int to;
    edge *next;
    edge(int _to):to(_to),next(NULL){}
};
struct vertex
{
    int Index;
    int Count;
    vertex():Count(-1),Index(-1){}
};
vertex city[_size];
int Map[_size][_size];
int Index = 0;
void dfs(int loca,int root)
{//cout << "loca = " << loca << ' ' << "root = " << root << endl;
    if (city[loca].Index==-1)
    {
        city[loca].Index = ++Index;
        for (int i=1;i<=n;i++)
            if (Map[loca][i]&&i!=root)
             {
                dfs(i,loca);
                city[loca].Index = min(city[i].Index,city[loca].Index);
             }
    }
};

int main()
{
    int i,j;
    scanf("%d%d%d",&n,&m,&k);
    for (i=0;i<m;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        Map[a][b] = Map[b][a] = 1;
    }
    int count = 0;
    for (i=1;i<=n;i++)
         if (city[i].Index==-1)
                dfs(i,i),count++;
    int Cnt[_size];
    while (k--)
    {
        int temp;
        scanf("%d",&temp);
        int Sum = 0;
        if (city[temp].Count==-1)
        {
        memset(Cnt,0,sizeof(Cnt));
        for (i=1;i<=n;i++)
            if (Map[temp][i]==1)
                Cnt[city[i].Index] = 1;
        for (i=1;i<=n;i++)
            Sum += Cnt[i];
        city[temp].Count = Sum;
        }
        Sum = city[temp].Count;
        printf("%d\n",count + Sum - 2);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值