题意:给出m个n的全排列,求一个n的全排列,满足对于i
(1)首先我们对 vis[ a[i] ][ a[j] ]++ ,求出a[i] 对 a[j] 的贡献。对vis[i][j] 和 vis[j][i]是否大于 一半 ,若大于就建立一条边,最后跑一边拓扑排序
(2)比赛的时候,将大于j 的数插入 s[j] 的集合中,然后对每一位进行筛选,若当前位置的数没有比他大的,则当前位置的数就为该数,然后将这个数从s[i] (i = 1 - > n)中删除这个数
依次循环,算的时间复杂度是0(k*n*n + n*n*log(n)),没想到超时了
比赛结束后,改成用树状数组维护,AC .... 没想到STL 时间复杂度真的是高
拓扑排序 AC code
#include
using namespace std;
const int N = 1e3 + 10;
int vis[N][N],a[N],in[N],ans[N],n;
vector<int>edge[N];
int topu()
{
int cont=0;
priority_queue<int,vector<int>,greater<int> >Q;
for(int i=1; i<=n; i++)
if(in[i]==0)
Q.push(i);
while(!Q.empty())
{
int u=Q.top();
Q.pop();
cont++;
ans[cont] = u;
for(int i = 0 ;i < edge[u].size(); i++)
{
int v = edge[u][i];
if(--in[v]==0)
Q.push(v);
}
}
if(cont<n)
return false;
return true;
}
int main()
{
int m;
while(~scanf("%d%d",&n,&m)&&n&&m)
{
memset(vis,0,sizeof(vis));
memset(in,0,sizeof(in));
for(int i = 1;i <= m;i++)
{
for(int j = 1;j <= n;j++)
scanf("%d",&a[j]);
for(int j = 1;j <= n;j++)
for(int k = j+1;k <= n;k++)
vis[a[j]][a[k]]++;
}
for(int i = 1; i <= n;i++)
for(int j = i + 1;j <= n;j++)
{
if(vis[i][j] > vis[j][i]) edge[i].push_back(j),in[j]++;
else if(vis[i][j] < vis[j][i]) edge[j].push_back(i),in[i]++;
}
if(topu())
{
for(int i = 1;i <= n;i++)
printf("%d%c",ans[i],i == n?'\n':' ');
}
else
puts("No solution");
for(int i = 1;i <= n;i++)
edge[i].clear();
}
return 0;
}
set超时代码:
#include
using namespace std;
const int N = 1e3 + 10;
int vis[N][N],a[N],vised[N];
set<int>s[N];
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m)&&n&&m)
{
for (int i=1;i<=n;i++)
s[i].clear();
memset(vis,0,sizeof(vis));
memset(vised,0,sizeof(vised));
for(int i = 1;i <= m;i++)
{
for(int j = 1;j <= n;j++)
scanf("%d",&a[j]);
for(int j = 1;j <= n;j++)
for(int k = j+1;k <= n;k++)
vis[a[j]][a[k]]++;
}
for(int i = 1; i <= n;i++)
for(int j = i + 1;j <= n;j++)
{
if(vis[i][j] > m/2) vis[i][j] = 1,vis[j][i] = 0,s[j].insert(i);
else if(vis[j][i] > m/2) vis[j][i] = 1,vis[i][j] = 0,s[i].insert(j);
else vis[i][j] = vis[j][i] = 0;
}
int ans[N],tot = 1;
while(tot <= n)
{
int flag = 0,now = 0;
for(int i = 1;i <= n;i++)
{
if(!vised[i])
{
if(s[i].empty())
{
flag = 1;
now = i;
break;
}
}
}
if(!flag) break;
ans[tot] = now;
vised[now] = 1;
for(int i = 1;i <= n;i++)
if(s[i].find(now) != s[i].end())
s[i].erase(s[i].find(now));
tot++;
}
if(tot <= n) puts("No solution");
else
{
for(int i = 1;i <= n;i++)
printf("%d%c",ans[i],i == n?'\n':' ');
}
}
return 0;
}
树状数组AC code:
#include
#define IT set::iterator
using namespace std;
const int N = 1e3 + 10;
int vis[N][N],a[N],vised[N],c[N][N],n;
int lowbit(int x){ return x&(-x);}
void update(int pos,int x,int y)
{
while(x <= n)
{
c[pos][x] += y;
x += lowbit(x);
}
}
int query(int pos,int x)
{
int ans = 0;
while(x)
{
ans += c[pos][x];
x -= lowbit(x);
}
return ans;
}
int main()
{
int m;
while(~scanf("%d%d",&n,&m)&&n&&m)
{
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
memset(vised,0,sizeof(vised));
for(int i = 1;i <= m;i++)
{
for(int j = 1;j <= n;j++)
scanf("%d",&a[j]);
for(int j = 1;j <= n;j++)
for(int k = j+1;k <= n;k++)
vis[a[j]][a[k]]++;
}
for(int i = 1; i <= n;i++)
for(int j = i + 1;j <= n;j++)
{
if(vis[i][j] > vis[j][i]) vis[i][j] = 1,vis[j][i] = 0,update(j,i,1);
else if(vis[j][i] > vis[i][j]) vis[j][i] = 1,vis[i][j] = 0,update(i,j,1);
else vis[i][j] = vis[j][i] = 0;
}
int ans[N],tot = 1;
while(tot <= n)
{
int flag = 0,now = 0;
for(int i = 1;i <= n;i++)
{
if(!vised[i])
{
if(!query(i,n))
{
flag = 1;
now = i;
break;
}
}
}
if(!flag) break;
ans[tot] = now;
vised[now] = 1;
for(int i = 1;i <= n;i++)
{
if(vis[now][i])
update(i,now,-1);
}
tot++;
}
if(tot <= n) puts("No solution");
else
{
for(int i = 1;i <= n;i++)
printf("%d%c",ans[i],i == n?'\n':' ');
}
}
return 0;
}