1.P1330 封锁阳光大学
思路:
染色判断是否能为二部图,若不是则输出"Impossible",否则输出该图的“最小覆盖数”,(开始用树状dp,只过了40),这里也可以染色法进行计算。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+11;
int n,m;
int f[N*2],nxt[N*2],to[N*2];
int cnt;
bool flag=1;
typedef long long ll;
void add(int u,int v)
{
nxt[++cnt]=f[u];
to[cnt]=v;
f[u]=cnt;
}
bool vis[N];
int col[N];
int sum[2];
bool pd(int x,int c)
{
if(vis[x])
{
if(col[x]==c)
return 1;
return 0;
}
vis[x]=1;
col[x]=c;
sum[c]++;
for(int i=f[x];i!=-1;i=nxt[i])
{
int v=to[i];
if(!vis[v])
{
if(!pd(v,1-c))
{
return 0;
}
}
if(col[x]==col[v])
return 0;
}
return 1;
}
int ans=0;
int main()
{
cin>>n>>m;
memset(f,-1,sizeof(f));
int x,y;
for(int i=1;i<=m;i++)
{
cin>>x>>y;
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
sum[1]=0,sum[0]=0;
if(!pd(i,1))
{
flag=0;
break;
}
ans+=min(sum[1],sum[0]);
}
}
if(!flag)
{
cout<<"Impossible";
}
else
{
cout<<ans;
}
return 0;
}
2.E. Cars
思路:2次构图,第一次用来判断是否为二部图,第二次用来拓扑。
代码:(debug 1w年)
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
vector<int> vec[N];
int x[N],y[N],op[N];
int col[N];
bool dfs(int x,int c){
col[x]=c;
for(int i:vec[x])
{
if(!col[i])
{
if(!dfs(i,3-c))
return 0;
}
if(col[i]==col[x])
return 0;
}
return 1;
}
vector<int>v[N];
int in[N],ans[N];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=m;i++)cin>>op[i]>>x[i]>>y[i],vec[x[i]].push_back(y[i]),vec[y[i]].push_back(x[i]);
for(int i=1;i<=n;i++)
{
if(!col[i])
{
if(!dfs(i,1))
{
cout<<"NO";
return 0;
}
}
}
for(int i=1;i<=m;i++){
if(col[x[i]]==2)
swap(x[i],y[i]);
if(op[i]==1)
v[x[i]].push_back(y[i]),in[y[i]]++;
else
v[y[i]].push_back(x[i]),in[x[i]]++;
}
queue<int>q;
int now=0;
for(int i=1;i<=n;i++)
if(!in[i])
q.push(i);
while(!q.empty()){
int u=q.front();q.pop();
ans[u]=++now;
for(int ne:v[u]){
in[ne]--;
if(!in[ne])q.push(ne);
}
}
if(now!=n)
{
cout<<"NO";
return 0;
}
cout<<"YES"<<endl;
for(int i=1;i<=n;i++)
{
if(col[i]==1)
cout<<"L ";
else
cout<<"R ";
cout<<ans[i]<<endl;
}
return 0;
}
3.D. Districts Connection
题意:n个节点,每个节点对应一个值。现在需要连n-1跳边使得每个节点之间是连通的,另外:值相同的节点不能连边。
思路:选取第一个节点为“中心”节点, 用2个A,B数组分别记录一第一个节点相同的节点的下标,另一个记录不同节点的下标。首先将B中的点全部与“中心”节点相连,若所构成的图(树)的节点个数<n, 则说明还有“相同值的节点”吗,没又连接进去,那么再从B中任意选一个节点node,将A全部连接到node上。
代码:
#include<bits/stdc++.h>
using namespace std;
int t;
int n;
void solve()
{
vector<int>a,b;
int x,base;
cin>>base;
a.push_back(1);
for(int i=2;i<=n;i++)
{
cin>>x;
if(x==base)
a.push_back(i);
else
b.push_back(i);
}
if(a.size()==n)
{
cout<<"NO"<<endl;
return;
}
cout<<"YES"<<endl;
for(int i=0;i<b.size();i++)
{
cout<<1<<" "<<b[i]<<endl;
}
if(1+b.size()<n)
{
for(int i=1;i<a.size();i++)
cout<<b[0]<<" "<<a[i]<<endl;
}
}
int main()
{
cin>>t;
while(t--)
{
cin>>n;
solve();
}
}
4.E. Hemose on the Tree
5.D. Circular Spanning Tree
6.B. Edge Weight Assignment
7.D. Carousel
思路: