逛公园
(park.pas/c/cpp/in/out)
时限:1 sec | 内存:64 MB
背景
SC theme Park 终于开业了,可爱的平平小朋友很荣幸的成为第一个游客。
公园设计强调,复杂就是美。scp大老板给他的公园设计了一个极其复杂的布局:
由于公园极大,而景点又很多,scp大老板在任意的两个景点之间都建造了一条星光小道,而且还为每条小道制定了方向。
题目描述
现在,平平从scp大老板那里得知公园总共有N个景点,并且已经知道了每一条星光小道的方向,但由于平平的方向感极差而RP又极低,于是一旦公园中出现回路,即存在环,平平便会迷路,并且无论怎么走都走不出去。
这样,scp大老板可就伤透脑筋了。为了使平平不会迷路,scp大老板决定改变其中M条星光小道的方向使得公园里不存在回路,但scp大老板又希望改变的小道的条数最少。由于很忙,腾不出时间,scp大老板只好请教即将参加noip的你。(注意:任意两个景点之间有且只有一条星光小道,且任意两条小道都是不相通的,即不能从一条小道不经过景点直接到达另一条小道)。
输入
第一行有一个整数N,表示有N个景点。
接下来是一张N*N的矩阵,第i+1行第j列表示有无从景点i指向景点j的星光小道(0表示没有,1表示有)。
输出
输出仅包括一行,即M的最小值。
输入样例 ( park.in)
4
0 0 0 0
1 0 1 0
1 0 0 1
1 1 0 0
输出样例 ( park.out)
1
数据规模
对于30%数据,1<=N<=10;
对于100%数据,1<=N<=20.
这套题比较难,实在没能做完。
有一个结论,完全图中如果没有环。那么我们将所有点按照出度排序,必然是0、1、2、3、4....n-1。
证明:必定有一个点出度为0,否则有环。因为是完全图,因此其他所有点必定向出度为0的点连一条边,因此出度至少为1。
而出度为1的点必定存在,否则有环。因此其它点出度至少为2。。依此类推。可证得所有点出度依次为0、1、2...n-1
此时便可以搜索。
搜索有两种思路比较清晰。
一种是我一开始采用的。TLE30。按出度升序枚举点i,每次枚举时遍历一次出度较小的点j,如果i到j无边,说明现在这条边是改变而来的的,答案加1。
另一种TLE60。按入度升序枚举点i,并把答案加上入度(这不是真正的入度,稍后说明),遍历所有的点j,如果i到j有边,则将j的入度减1,表示只记录原来没有而是新变来的入边。
TLE30:
#include <cstdio>
#include <algorithm>
long c = 0;
long ans = 0x7f7f7f7f;
char map[30][30];
bool used[30];
long bs[30];
long stack[30];
long top = 0;
long n;
struct node
{
long i;
long c;
bool operator<(const node& n2)const{return c<n2.c;}
}chudu[30];
void dfs(long nc,long c)
{
if (nc >= ans)
return;
if (c == n+1)
{
ans = ans<nc?ans:nc;
return;
}
for (long ii=1;ii<n+1;ii++)
{
long i = chudu[ii].i;
if (!used[i])
{
used[i] = 1;
stack[++top] = i;
long tmp = 0;
for (long j=1;j<c;j++)
{
tmp += map[stack[j]][i];
}
dfs(nc+tmp,c+1);
top --;
used[i] = 0;
}
}
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
scanf("%ld",&n);
for (long i=1;i<n+1;i++)
{
chudu[i].i = i;
for (long j=1;j<n+1;j++)
{
do map[i][j] = getchar()-'0';
while (map[i][j]!=0&&map[i][j]!=1);
chudu[i].c += map[i][j];
}
}
std::sort(chudu+1,chudu+n+1);
dfs(0,1);
printf("%ld",ans);
return 0;
}
TLE60:
#include <cstdio>
long ans = 0;
long minans = 0x7f7f7f7f;
long into[60];
bool used[60];
char map[60][60];
long n;
void dfs(long u)
{
if (u == n)
{
minans = minans<ans?minans:ans;
return;
}
for (long i=1;i<n+1;i++)
{
if (!used[i])
{
ans += into[i];
if (ans < minans)
{
used[i] = true;
for (long j=1;j<n+1;j++)
if (map[i][j]) into[j]--;
dfs(u+1);
for (long j=1;j<n+1;j++)
if (map[i][j]) into[j]++;
used[i] = false;
}
ans -= into[i];
}
}
}
int main()
{
freopen("park.in","r",stdin);
freopen("park.out","w",stdout);
scanf("%ld",&n);
for (long i=1;i<n+1;i++)
{
for (long j=1;j<n+1;j++)
{
do map[i][j] = getchar() - '0';
while (map[i][j]!=1&&map[i][j]!=0);
if (map[i][j]){into[j]++;}
}
}
dfs(0);
printf("%ld",minans);
return 0;
}