P1330 封锁阳光大学(搜索+图的链式向前星存储)

给你一幅图,问你最少占领几个点,能够封锁阳光大学,但是不能占领一条边的两个点

就是每条边有且只有一个点能被占领,这么一来,每个连通分量只可能有两个方案(占领变不占领),所以直接搜,加上少的就好了

 1 #include<iostream>
 2 using namespace std;
 3 const int N=1e5+100;
 4 int cnt=0;
 5 struct node
 6 {
 7     int to;//到的点
 8     int from;//出发点相同的边在数组中的位置
 9 }edge[N];
10 int head[N];
11 void add(int a,int b)
12 {
13     cnt++;
14     edge[cnt].to=b;//这条边到达的点
15     edge[cnt].from=head[a];//存下目前最新的和我同出发点的边所在位置(因为我就要替换他了)
16     head[a]=cnt;
17 }//链式向前星(难)
18 
19 bool used[N];
20 int color[N];
21 int sum[2];
22 bool dfs(int now,int col)
23 {
24     if(used[now])
25     {
26         if(color[now]==col)//如果走完一遍回来,发现自个儿的颜色还得变,那就是impossible了
27         {
28             return true;
29         }
30         return false;
31     }
32     used[now]=true;//标记
33     color[now]=col;//记录现在在的点的颜色
34     sum[col]++;//这种颜色的点加一
35     bool flag=1;
36     for(int i=head[now];i!=0&&flag;i=edge[i].from)//遍历所有的边,可以理解为深度遍历
37     {
38         if(!dfs(edge[i].to,!col))//如果下一个点出问题了,一路返回false
39             flag=0;
40     }
41     return flag;
42 }
43 int main(void)
44 {
45     int n,m;
46     cin>>n>>m;
47     for(int i=1;i<=m;i++)
48     {
49         int a,b;
50         cin>>a>>b;
51         add(a,b);//无向图
52         add(b,a);
53     }
54     int ans=0;
55     for(int i=1;i<=n;i++)
56     {
57         if(used[i])
58             continue;
59         sum[0]=sum[1]=0;//初始化
60         if(!dfs(i,0))//如果不能完成染色,直接输出im
61         {
62             cout<<"Impossible";
63             return 0;
64         }
65         ans+=min(sum[0],sum[1]);//加上小的
66     }
67     cout<<ans;
68     return 0;
69 }
原文地址:https://www.cnblogs.com/greenofyu/p/12229916.html