B
题意:给一个n排列, 和一个nxn矩阵,矩阵中元素代表那些位置上的元素可以互相交换,要搞出字典序最小的排列。。
思路:floyd一遍,然后位置从小到大,将能放在该位上最小的元素与该位置上现在的元素交换,,如果两个位置之间存在一条路径,是可以进行一系列交换使得最后等效于他们直接交换。。一开始没想到,用了个vis禁掉已经换过的位置,然后模拟交换过程。。。直接FST。。
#include<bits/stdc++.h>
using namespace std;
#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
typedef long long LL;
const int Maxn = 300;
int n;
int p[Maxn+5];
int d[Maxn+5][Maxn+5];
char buf[1000];
bool cmp(int lhs, int rhs) {
return p[lhs] < p[rhs];
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
SPEED_UP
cin >> n;
rep(i, 1, n) {
cin >> p[i];
}
rep(i, 1, n) {
cin >> buf;
rep(j, 1, n)
d[i][j] = buf[j-1]-'0';
}
rep(i, 1, n) d[i][i] = 1;
rep(k, 1, n)
rep(i, 1, n)
rep(j, 1, n)
if (i!=j)
d[i][j] |= d[i][k]&d[k][j];
rep(r, 1, n) {
int pos = r, _min = p[r];
rep(i, r+1, n)
if (d[r][i] && p[i] < _min) {
pos = i;
_min = p[i];
}
swap(p[r], p[pos]);
}
rep(i, 1, n-1) cout << p[i] << ' ';cout << p[n];
return 0;
}
C
题意:略。。。
思路:
初始顺序,第一个放的一定是第一次出现的元素。假设存在一个最优序列,第一个元素不是第一次出现的元素,那个可以把第一次出现的元素拿到顶上,这个新的序列显然优于刚才的序列。沿用这个思路,我们可以证明最优序列元素的顺序恰好是按照第一次访问顺序来的。。
#include<bits/stdc++.h>
using namespace std;
#define SPEED_UP iostream::sync_with_stdio(false);
#define FIXED_FLOAT cout.setf(ios::fixed, ios::floatfield);
#define rep(i, s, t) for(int (i)=(s);(i)<=(t);++(i))
#define urep(i, s, t) for(int (i)=(s);(i)>=(t);--(i))
typedef long long LL;
const int Maxn = 1005;
int w[Maxn], d[Maxn], p[Maxn], vis[Maxn];
int n, m;
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
SPEED_UP
cin >> n >> m;
rep(i, 1, n) cin >> w[i];
rep(i, 1, m) cin >> d[i];
int idx = 1;
memset(vis, 0, sizeof(vis));
rep(i, 1, m)
if (!vis[d[i]]) {
vis[d[i]] = 1;
p[idx++] = d[i];
}
list<int> li;
long long ans = 0;
rep(i, 1, n) li.push_back(p[i]);
rep(i, 1, m) {
int aim = d[i];
for (list<int>::iterator it=li.begin();it!=li.end();++it) {
if (*it != aim) {
ans += w[*it];
}
else {
li.erase(it);
li.insert(li.begin(), aim);
break;
}
}
}
cout << ans;
//rep(i, 1, n) cout << p[i] << ' ';cout << endl;
return 0;
}

本文提供两道算法竞赛题目的解答思路及代码实现。第一题利用Floyd算法寻找可达路径,并通过比较不同位置元素大小实现字典序最小排列;第二题采用贪心策略,通过记录元素首次出现顺序来构造最优解。
516

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



