https://codeforces.com/contest/1394/problem/B
我们知道对于C的任意一组选择,最后每个点都只有一个出度,然而这题要保证最后所有点可以走到自己,那么这等价于每个点都只有一个出度和一个入度。
然后我们枚举每条边(u,v,l),把{out[u],rank(l)}给v,表示如果最后选择为c[out[u]]=rank(l),那么v这个点将会多一个入度,显然对于一个点v,所有这些选择之间必须选择一个,但不能选择多个,因为必须保证入度为1,所以他们是互斥了,用一个set表示每一个c[i]=j与哪些c[i2]=j2互斥
然后dfs的时候边选择边把当前选择互斥的那些点标记上,而且还要记录一下每个选择可以让多少点入度为1,要保证所有点都能入度为1.
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
int n,m,cas,k,cnt,tot,ans;
int a[maxl],out[maxl],c[maxl];
struct ed{int u,v,l;};
vector<ed> e[maxl];
ll in[100][100];int num[100][100];
typedef pair<int,int> p;
set <p> s[10][10];
vector<p> b[maxl];
inline bool cmp(const ed &a,const ed &b)
{
return a.l<b.l;
}
inline void prework()
{
scanf("%d%d%d",&n,&m,&k);
int u,v,l;
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&l);
out[u]++;
e[u].push_back(ed{u,v,l});
}
for(int i=1;i<=n;i++)
sort(e[i].begin(),e[i].end(),cmp);
for(int i=1;i<=n;i++)
{
l=e[i].size();
for(int j=0;j<l;j++)
b[e[i][j].v].push_back({out[e[i][j].u],j+1});
}
}
inline void dfs(int x,int res)
{
if(x>k)
{
if(res==0)
ans++;
return;
}
if(c[x]>0)
{
if(!in[x][c[x]])
{
a[x]=c[x];
for(p d:s[x][c[x]])
++in[d.first][d.second];
dfs(x+1,res-num[x][c[x]]);
a[x]=0;
for(p d:s[x][c[x]])
--in[d.first][d.second];
}
}
else
{
for(int i=1;i<=x;i++)
if(!in[x][i])
{
a[x]=i;
for(p d:s[x][i])
++in[d.first][d.second];
dfs(x+1,res-num[x][i]);
for(p d:s[x][i])
--in[d.first][d.second];
a[x]=0;
}
}
}
inline void mainwork()
{
int u,v,l;ans=0;
for(int i=1;i<=n;i++)
{
l=b[i].size();
if(l==0)
return;
else if(l==1)
{
u=b[i][0].first;num[u][b[i][0].second]++;
if(c[u]==0)
c[b[i][0].first]=b[i][0].second;
else if(c[u]!=b[i][0].second)
return;
}
else
{
sort(b[i].begin(),b[i].end());
for(int j=0;j<l;j++)
if(j>1 && b[i][j]==b[i][j-1])
in[b[i][j].first][b[i][j].second]++;
b[i].erase(unique(b[i].begin(),b[i].end()),b[i].end());
l=b[i].size();
for(int j=0;j<l;j++)
{
num[b[i][j].first][b[i][j].second]++;
for(int k=0;k<l;k++)
if(j!=k)
{
u=b[i][j].first;
v=b[i][k].first;
s[u][b[i][j].second].insert(b[i][k]);
s[v][b[i][k].second].insert(b[i][j]);
}
}
}
}
dfs(1,n);
}
inline void print()
{
printf("%d\n",ans);
}
int main()
{
int t=1;
//scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}
本文详细解析了Codeforces竞赛中的一道题目B,探讨了如何通过枚举边(u,v,l)并利用set来表示不同选择之间的互斥关系,进而解决所有点能够走到自己的问题。通过DFS遍历和记录每种选择下点的入度,确保最终方案的可行性。
470

被折叠的 条评论
为什么被折叠?



