题意:给出m个n的全排列,求一个n的全排列,满足对于i<j,至少存在一半的全排列中,ai排在aj的前面,求字典序最小方案,或者是无解。
(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 <bits/stdc++.h> 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?' ':' '); } else puts("No solution"); for(int i = 1;i <= n;i++) edge[i].clear(); } return 0; }
set超时代码:
#include <bits/stdc++.h> 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?' ':' '); } } return 0; }
树状数组AC code:
#include <bits/stdc++.h> #define IT set<int>::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?' ':' '); } } return 0; }