#include
using namespace std;
queue<int> q;
const int N = 1e4 + 10;
int n,m;
int v[N];
int dp[N];
//bool vis[N][110];
pair<int, int> pre[N][110];
bool cmp(int a,int b) {
return a > b;
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> v[i];
}
sort(v + 1, v + 1 + n,cmp);
for(int i = 1; i <= n; i++) {
for(int j = m; j >= v[i]; j--) {
// dp[j] = max(dp[j],dp[j - v[i]] + v[i]);
if(dp[j] <= dp[j-v[i]] + v[i]) {
dp[j] = dp[j-v[i]] + v[i];
pre[i][j] = make_pair(i-1, j-v[i]);
// vis[i][j] = true;
} else {
pre[i][j] = make_pair(i-1, j);
}
}
}
if(dp[m] == m) {
pair<int, int> p = make_pair(n, m);
while (p.first != 0) {
int x = pre[p.first][p.second].first;
int y = pre[p.first][p.second].second;
if (y != p.second) {
if (p.second != m) cout << ' ';
cout << v[p.first];
}
p = make_pair(x, y);
}
} else {
cout << "No Solution";
}
}
暴力解法:()
也可以过很多,先排个序,优先全选最小的,所以只要存在第一种方案即是最优的
#include
using namespace std;
const int N = 1e4 + 10;
int n,m;
int v[N];
int path[N];
int idx;
bool vis[N];
bool ok = false;
void dfs(int u,int sum) {
if(u > n || sum > m) {
return;
}
if(sum == m) {
ok = true;
int ct = 0;
for(int i = 1; i <= n; i++) {
if(vis[i]) {
if(ct != 0) {
cout << " ";
}
cout << v[i];
ct++;
}
}
exit(0);
}
vis[u] = true;
dfs(u + 1,sum + v[u]);
vis[u] = false;
dfs(u + 1,sum);
}
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
cin >> v[i];
}
sort(v+1,v+1+n);
dfs(0,0);
cout << "No Solution";
}
需要注意在peekMedian时,进行排序时,我们不能对进行模拟的数组直接进行排序,这样排序后会影响后续操作,我们应该再开一个辅助数组进行进行排序和输出。
#include
using namespace std;
const int N = 1e5 + 10;
int st[N];
int cst[N];
int idx;
int main() {
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
string op;
int x;
cin >> op;
if(op == "Pop") {
if(idx <= 0) {
cout << "Invalid" << endl;
} else {
cout << st[idx] << endl;
--idx;
}
} else if(op == "Push") {
cin >> x;
st[++idx] = x;
} else {
if(idx == 0) {
cout << "Invalid" << endl;
} else {
for(int i = 1; i <= idx; i++){
cst[i] = st[i];
}
sort(cst+1,cst+1+idx);
if(idx % 2 == 0){
cout << cst[idx/2] << endl;
}else{
cout << cst[idx/2 + 1] << endl;
}
}
}
}
}
法二:采用vector顺序插入,lower_bound(),
#include
using namespace std;
vector<int> num ;
stack<int> st ;
vector<int>::iterator it;
int main() {
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
string op;
int x;
cin >> op;
if(op == "Pop") {
if(num.size() == 0) {
cout << "Invalid" << endl;
} else {
cout << st.top() << endl;
it = lower_bound(num.begin(),num.end(),st.top());
num.erase(it);
st.pop();
}
} else if(op == "Push") {
cin >> x;
it = lower_bound(num.begin(),num.end(),x);
num.insert(it,x);
st.push(x);
} else {
if(num.size() == 0) {
cout << "Invalid" << endl;
} else {
int t = 0;
if(num.size()%2 == 0) {
t = num.size()/2;
} else {
t = (num.size() + 1) / 2;
}
cout << num[t - 1] << endl;
}
}
}
}
对于每个有相同爱好的人我们进行merge,并维护每一个集合的大小,对于判断两个人是否有相同爱好,我们暴力就可以过,最后对于每个集合,将集合大小存入multiset,进行从大到小排序即可
#include
using namespace std;
vector<int> a[1100];
int n;
int fa[1100];
int sz[1100];
multiset<int,greater<int> > st;
multiset<int>::iterator it;
void init() {
for(int i = 1; i <= 1000; i++) {
fa[i] = i;
sz[i] = 1;
}
}
bool judge(int x,int y) {
for(int i = 0; i < a[x].size(); i++) {
for(int j = 0; j < a[y].size(); j++) {
if(a[x][i] == a[y][j]) {
return true;
}
}
}
return false;
}
int find(int x) {
if(fa[x] == x) {
return x;
}
return fa[x] = find(fa[x]);
}
void merge(int u,int v) {
int fu = find(u);
int fv = find(v);
if(fu != fv) {
fa[fu] = fv;
sz[fv] += sz[fu];
}
}
int main() {
cin >> n;
init();
for(int i = 1; i <= n; i++) {
int k;
cin >> k;
getchar();
for(int j = 1; j <= k; j++) {
int x;
cin >> x;
a[i].push_back(x);
}
}
for(int i = 1; i <= n; i ++) {
for(int j = i; j <= n; j++) {
if(judge(i,j)) {
merge(i,j);
}
}
}
for(int i = 1; i <= n; i++){
if(fa[i] == i){
// cout << sz[i] << " ";
st.insert(sz[i]);
}
}
cout << st.size() << endl;
for(it = st.begin(); it != st.end(); it++){
if(it != st.begin()){
cout << " ";
}
cout << *it;
}
}
#include
using namespace std;
int idx;
int dx[6] = {0,0,-1,1,0,0};
int dy[6] = {-1,1,0,0,0,0};
int dz[6] = {0,0,0,0,-1,1};
int a[80][1300][150];
bool vis[80][1300][150];
int ans;
int cnt;
int m,n,l,t;
bool check(int z,int x,int y) {
if(x >= 1 && x <= m && y >= 1 && y <= n && z >= 1 && z <= l && a[z][x][y] == 1 && !vis[z][x][y]){
return true;
}
return false;
}
void dfs(int z,int x,int y) {
for(int k = 0; k <= 5; k++) {
int nx = x + dx[k];
int ny = y + dy[k];
int nz = z + dz[k];
if(check(nz,nx,ny)) {
cnt++;
vis[nz][nx][ny] = true;
dfs(nz,nx,ny);
}
}
}
int main() {
cin >> m >> n >> l >> t;
for(int z = 1; z <= l; z++) {
for(int x = 1; x <= m; x++) {
for(int y = 1; y <= n; y++) {
cin >> a[z][x][y];
}
}
}
for(int z = 1; z <= l; z++) {
for(int x = 1; x <= m; x++) {
for(int y = 1; y <= n; y++) {
if(!vis[z][x][y] && a[z][x][y] == 1) {
cnt = 1;
vis[z][x][y] = true;
dfs(z,x,y);
if(cnt >= t)
ans += cnt;
}
}
}
}
cout << ans;
}
法2:三维bfs
#include
using namespace std;
int idx;
int dx[6] = {0,0,-1,1,0,0};
int dy[6] = {-1,1,0,0,0,0};
int dz[6] = {0,0,0,0,-1,1};
int a[80][1300][150];
bool vis[80][1300][150];
int ans;
int cnt;
int m,n,l,t;
struct node {
int z,x,y;
};
queue<node> q;
bool check(int z,int x,int y) {
if(x >= 1 && x <= m && y >= 1 && y <= n && z >= 1 && z <= l && a[z][x][y] == 1 && !vis[z][x][y]) {
return true;
}
return false;
}
void bfs(int z,int x,int y) {
node t = {z,x,y};
q.push(t);
while(!q.empty()) {
node cur = q.front();
int z = cur.z;
int x = cur.x;
int y = cur.y;
q.pop();
cnt++;
for(int k = 0; k <= 5; k++) {
int nx = x + dx[k];
int ny = y + dy[k];
int nz = z + dz[k];
if(check(nz,nx,ny)) {
vis[nz][nx][ny] = true;
node temp = {nz,nx,ny};
q.push(temp);
}
}
}
}
int main() {
cin >> m >> n >> l >> t;
for(int z = 1; z <= l; z++) {
for(int x = 1; x <= m; x++) {
for(int y = 1; y <= n; y++) {
cin >> a[z][x][y];
}
}
}
for(int z = 1; z <= l; z++) {
for(int x = 1; x <= m; x++) {
for(int y = 1; y <= n; y++) {
if(!vis[z][x][y] && a[z][x][y] == 1) {
cnt = 0;
vis[z][x][y] = 1;
bfs(z,x,y);
if(cnt >= t)
ans += cnt;
}
}
}
}
cout << ans;
}
思路:以垃圾桶为源点分别进行dijkstra,存下来可行的答案,排序输出即可
需要处理:因为垃圾桶为G1-Gm所以我们将垃圾桶映射到n+1到n+m即可
(1)需要注意每次选取的最小值应该是!vis[i]
(2)每次都需要进行初始化
坐标映射:
int isP(string x) {
int index;
if(x[0] == 'G') {
index = n + stoi(x.substr(1));
} else {
index = stoi(x);
}
return index;
}
#include
using namespace std;
const int N = 1e3 + 200;
const int Inf = 1e9;
int a[N][N];
bool vis[N];
int dis[N];
int n,m,k,ds;
struct node {
int id;
double minn;
double ave;
} p[N];
bool cmp(node a,node b) {
if(a.minn == b.minn) {
if(fabs(a.ave - b.ave) <= 1e-8) {
return a.id < b.id;
} else {
return a.ave < b.ave;
}
}else{
return a.minn > b.minn;
}
}
int idx;
void dijkstra(int s) {
for(int i = 1; i <= m + n; i++) {
vis[i] = false;
dis[i] = Inf;
}
dis[s] = 0;
for(int i = 1; i <= m + n; i++) {
int mini = -1;
int minn = Inf;
for(int j = 1; j <= m + n; j++) {
if(!vis[j] && dis[j] < minn) {
minn = dis[j];
mini = j;
}
}
if(mini == -1) {
break;
}
vis[mini] = true;
for(int j = 1; j <= m + n; j++) {
if(!vis[j] && dis[j] > dis[mini] + a[mini][j]) {
dis[j] = dis[mini] + a[mini][j];
}
}
}
int midis = Inf;
bool ok = true;
double sum = 0;
for(int i = 1; i <= n; i++) {
// cout << dis[i] << endl;
midis = min(midis,dis[i]);
if(dis[i] > ds) {
ok = false;
break;
}
sum += dis[i];
}
if(ok) {
p[++idx] = {s - n,midis,sum/n};
}
}
void init() {
for(int i = 1; i < N; i++) {
for(int j = 1; j < N; j++) {
if(i != j) {
a[i][j] = Inf;
}
}
}
}
int isP(string x) {
int index;
if(x[0] == 'G') {
index = n + stoi(x.substr(1));
} else {
index = stoi(x);
}
return index;
}
void read() {
string p1,p2;
int dist;
cin >> p1 >> p2 >> dist;
int x = isP(p1);
int y = isP(p2);
a[x][y] = a[y][x] = dist;
}
int main() {
cin >> n >> m >> k >> ds;
init();
for(int i = 1; i <= k; i++) {
read();
}
for(int i = n + 1; i <= n + m; i++) {
dijkstra(i);
}
if(idx == 0) {
cout << "No Solution";
} else {
sort(p + 1,p + 1 + idx,cmp);
cout << "G" << p[1].id << endl;
printf("%.1f %.1f",p[1].minn,p[1].ave);
}
}
刚开始想着用dfs,发现有两个点过不了,
由上图可以直到,dfs是深度优先,我们会觉得5是最远的,其实4和5是一样远的,但是答案要输出编号更小的,所以正确答案为4,很明显本题能看出来传递是一层一层的,所以这种问题用bfs更好,第一次找到某点一定是路径最短的,所以我们采用bfs进行查找,需要注意每次标记,特别是标记起始那个点,要不会死循环。
#include
using namespace std;
const int N = 1e4 + 10;
int h[N];
int ne[4*N];
int to[4*N];
int n,m,k;
int idx;
bool vis[N];
struct node {
int id;
int dis;
} a[N];
int cnt;
queue<node> q;
bool cmp(node o1,node o2) {
if(o1.dis == o2.dis) {
return o1.id < o2.id;
} else {
return o1.dis > o2.dis;
}
}
//void dfs(int u,int dep,int pre){
//
// for(int i = h[u]; i != 0; i = ne[i]){
// int j = to[i];
// if(!vis[j]){
// vis[j] = true;
// a[cnt++] = {j,dep + 1};
// dfs(j,dep + 1,u);
// vis[j] = false;
// }
// }
//}
void bfs(int u) {
vis[u] = true;
node aa = {u,0};
q.push(aa);
while(!q.empty()) {
// cout << q.size();
node t = q.front();
q.pop();
int uu = t.id;
for(int i = h[uu];i != 0 ; i = ne[i]) {
int j = to[i];
// cout << j;
if(!vis[j]) {
vis[j] = true;
q.push({j,t.dis + 1});
node cur = {j,t.dis + 1};
a[cnt++] = cur;
}
}
}
// cout << endl;
}
void add(int u,int v) {
ne[++idx] = h[u];
to[idx] = v;
h[u] = idx;
}
void init() {
cnt = 0;
for(int i = 0; i < N; i++) {
vis[i] = false;
}
}
int main() {
cin >> n >> m >> k;
for(int i = 1; i <= m; i++) {
int x,y;
cin >> x >> y;
add(x,y);
add(y,x);
}
for(int i = 1; i <= k; i++) {
int x;
cin >> x;
init();
cnt = 0;
// dfs(x,0,-1);
bfs(x);
if(cnt == 0) {
cout << "0" << endl;
} else {
sort(a,a + cnt,cmp);
cout << a[0].id << endl;
}
}
}
首先根据规则建树,并且在建树的过程中,我们就可以直到是不是完全二叉树,只要满足最大节点编号等于结点数就可以做到是完全二叉树(需要注意的是:N个点顺序插入空的树,说明第一个插入的点就是根节点,不需要自己去调整)
#include
using namespace std;
const int N = 1e4 + 10;
int t[100];
int n;
int root;
int maxn = 1;
void insert(int x) {
int id = 1;
while(t[id] != 0) {
if(x > t[id]) {
id = id * 2;
} else {
id = id * 2 + 1;
}
}
t[id] = x;
maxn = max(maxn,id);
}
int main() {
cin >> n;
cin >> root;
t[1] = root;
for(int i = 2; i <= n; i++) {
int x;
cin >> x;
insert(x);
}
if(maxn == n) {
cout << root;
for(int i = 2; i <= maxn; i++) {
if(t[i] != 0) {
cout << " " << t[i];
}
}
cout << endl << "YES";
} else {
cout << root;
for(int i = 2; i <= maxn; i++) {
if(t[i] != 0) {
cout << " " << t[i];
}
}
cout << endl << "NO";
}
}