版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/belous_zxy/article/details/88645294
2019/03/18 完成01-02
2019/03/19 完成03
2019/03/20 完成04
2019/03/21 完成05(unordered_set)
2019/03/22 完成05(手写哈希),06
2019/03/23 完成07
L2-001 紧急救援(C++11)
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
const int INF{0x3f3f3f3f};
int main(int argc, char *argv[])
{
cin.sync_with_stdio(false);
int N, M, S, D;
cin >> N >> M >> S >> D;
vector<int> vec(N);
for (int i = 0; i != N; ++i)
cin >> vec[i];
vector<vector<intpair>> road(N);
for (int i = 0; i != M; ++i)
{
int mbeg, mend, mvel;
cin >> mbeg >> mend >> mvel;
road[mbeg].push_back({mend, mvel});
road[mend].push_back({mbeg, mvel});
}
vector<int> dijkstra(N, INF), mov(N), cross(N), mins(N);
vector<bool> known(N, false);
dijkstra[S] = 0;
mov[S] = vec[S];
cross[S] = -1;
mins[S] = 1;
while (1)
{
int minval{INF}, minindex{-1};
for (int i = 0; i != N; ++i)
{
if (known[i] == false && dijkstra[i] != INF && dijkstra[i] < minval)
{
minindex = i;
minval = dijkstra[i];
}
}
if (minindex == -1)
break;
known[minindex] = true;
for (const auto &i : road[minindex])
{
if (dijkstra[minindex] + i.second < dijkstra[i.first])
{
dijkstra[i.first] = dijkstra[minindex] + i.second;
mov[i.first] = mov[minindex] + vec[i.first];
cross[i.first] = minindex;
mins[i.first] = mins[minindex];
}
else if (dijkstra[minindex] + i.second == dijkstra[i.first])
{
if (mov[minindex] + vec[i.first] > mov[i.first])
{
mov[i.first] = mov[minindex] + vec[i.first];
cross[i.first] = minindex;
}
mins[i.first] += mins[minindex];
}
}
}
cout << mins[D] << ' ' << mov[D] << endl;
stack<int> ST;
int tD{D};
ST.push(D);
while (cross[tD] != -1)
{
ST.push(cross[tD]);
tD = cross[tD];
}
bool fis = true;
while (!ST.empty())
{
if (fis)
fis = false;
else
cout << ' ';
cout << ST.top();
ST.pop();
}
cout << endl;
return EXIT_SUCCESS;
}
Dijkstra算法
L2-002 链表去重(C++11)
#include <iostream>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
int main(int argc, char *argv[])
{
int beginnode, cnt;
scanf("%d%d", &beginnode, &cnt);
vector<intpair> LinkNode(100000);
vector<int> book(100001);
while (cnt--)
{
int beg, val, next;
scanf("%d%d%d", &beg, &val, &next);
LinkNode[beg] = {val, next};
}
int disp{-1}, dispold{beginnode}, temp{-1}, temp2{-1};
while (beginnode != -1)
{
if (book[abs(LinkNode[beginnode].first)])
{
if (disp == -1)
disp = temp = beginnode;
else
{
LinkNode[temp].second = beginnode;
temp = beginnode;
}
}
else
{
if (temp2 != -1)
LinkNode[temp2].second = beginnode;
temp2 = beginnode;
book[abs(LinkNode[beginnode].first)] = true;
}
beginnode = LinkNode[beginnode].second;
}
LinkNode[temp2].second = LinkNode[temp].second = -1;
beginnode = dispold;
if (beginnode != -1)
{
printf("%05d %d", beginnode, LinkNode[beginnode].first);
beginnode = LinkNode[beginnode].second;
while (beginnode != -1)
{
printf(" %05d\n%05d %d", beginnode, beginnode, LinkNode[beginnode].first);
beginnode = LinkNode[beginnode].second;
}
printf(" -1\n");
}
beginnode = disp;
if (beginnode != -1)
{
printf("%05d %d", beginnode, LinkNode[beginnode].first);
beginnode = LinkNode[beginnode].second;
while (beginnode != -1)
{
printf(" %05d\n%05d %d", beginnode, beginnode, LinkNode[beginnode].first);
beginnode = LinkNode[beginnode].second;
}
printf(" -1\n");
}
return EXIT_SUCCESS;
}
考察数组模拟链表;上面的实现的稍有麻烦,完全修正了链表地址,分开了两个链表;然而根据题目输出要求,这是没有必要的!可以直接开两个vector存储下两个链表的地址,如下。
#include <iostream>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
intpair LinkNode[100000];
int book[100001]{0};
int main(int argc, char *argv[])
{
int beginnode, cnt;
scanf("%d%d", &beginnode, &cnt);
while (cnt--)
{
int beg, val, next;
scanf("%d%d%d", &beg, &val, &next);
LinkNode[beg] = {val, next};
}
vector<int> a, b;
while (beginnode != -1)
{
if (book[abs(LinkNode[beginnode].first)])
b.push_back(beginnode);
else
{
a.push_back(beginnode);
book[abs(LinkNode[beginnode].first)] = true;
}
beginnode = LinkNode[beginnode].second;
}
if (!a.empty())
{
printf("%05d %d", a[0], LinkNode[a[0]].first);
for (decltype(a.size()) i = 1; i != a.size(); ++i)
printf(" %05d\n%05d %d", a[i], a[i], LinkNode[a[i]].first);
printf(" -1\n");
}
if (!b.empty())
{
printf("%05d %d", b[0], LinkNode[b[0]].first);
for (decltype(b.size()) i = 1; i != b.size(); ++i)
printf(" %05d\n%05d %d", b[i], b[i], LinkNode[b[i]].first);
printf(" -1\n");
}
return EXIT_SUCCESS;
}
L2-003 月饼
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
using mypair = pair<double, double>;
bool mypaircompare(const mypair &a, const mypair &b)
{
return a.second > b.second;
}
int main(int argc, char *argv[])
{
int cnt, need;
scanf("%d%d", &cnt, &need);
vector<mypair> vec(cnt);
for (int i = 0; i < cnt; ++i)
scanf("%lf", &vec[i].first);
for (int i = 0; i < cnt; ++i)
{
double temp;
scanf("%lf", &temp);
vec[i].second = temp / vec[i].first;
}
sort(vec.begin(), vec.end(), mypaircompare);
double cost{0.0};
for (int i = 0; i < cnt; ++i)
{
if (need >= vec[i].first)
{
need -= vec[i].first;
cost += vec[i].first * vec[i].second;
if (!need)
break;
}
else
{
cost += need * vec[i].second;
break;
}
}
printf("%.2lf\n", cost);
return EXIT_SUCCESS;
}
简单的贪心;老题目了,需要注意库存量和总售价都是浮点数,样例输入是整数具有迷惑性…哈哈
L2-004 这是二叉搜索树吗?
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int array[1001]{0};
vector<int> T;
bool mir;
bool buildtree(int beg, int ed)
{
if (beg > ed)
return true;
int root{array[beg]}, mid;
int temp{beg + 1};
if (mir)
{
while (temp <= ed && array[temp] >= root)
++temp;
mid = temp - 1;
while (temp <= ed && array[temp] < root)
++temp;
}
else
{
while (temp <= ed && array[temp] < root)
++temp;
mid = temp - 1;
while (temp <= ed && array[temp] >= root)
++temp;
}
if (temp != ed + 1)
return false;
bool re = buildtree(beg + 1, mid) && buildtree(mid + 1, ed);
T.push_back(root);
return re;
}
int main(int argc, char *argv[])
{
int cnt;
scanf("%d", &cnt);
for (int i = 1; i <= cnt; ++i)
scanf("%d", &array[i]);
mir = false;
bool isp{true};
if (!buildtree(1, cnt))
{
mir = true;
T.clear();
isp = buildtree(1, cnt);
}
if (isp)
{
printf("YES\n");
for (auto i = T.begin(); i != T.end(); ++i)
{
if (i != T.begin())
putchar(' ');
printf("%d", *i);
}
putchar('\n');
}
else
printf("NO\n");
return EXIT_SUCCESS;
}
根据二叉搜索树的前序遍历,输出后序遍历。因为只需要输出后序遍历,所以我们并不需要真正的建树,按照左子树、右子树、根节点的次序把后序遍历存储下来就可以啦。
基础题上加了个花样,即可能是“镜像二叉搜索树”;先假定不是镜像的,遍历一次;如果遍历失败,就假定是镜像的,再尝试一次,两次都失败输出“NO”,成功就输出存储后序遍历的vector。
L2-005 集合相似度
#include <algorithm>
#include <iostream>
#include <set>
#include <unordered_set>
#include <vector>
using namespace std;
int main(int argc, char *argv[])
{
int cnt;
scanf("%d", &cnt);
vector<unordered_set<int>> SET(cnt);
for (int i = 0; i != cnt; ++i)
{
int ind;
scanf("%d", &ind);
while (ind--)
{
int temp;
scanf("%d", &temp);
SET[i].insert(temp);
}
}
scanf("%d", &cnt);
while (cnt--)
{
int a, b;
scanf("%d%d", &a, &b);
--a, --b;
int sum{0};
for (const auto &i : SET[a])
if (SET[b].find(i) != SET[b].end())
++sum;
printf("%.2lf%%\n", (sum * 1.0) / (SET[a].size() + SET[b].size() - sum) * 100.0);
}
return EXIT_SUCCESS;
}
这是专门为STL库准备的题啊?…元素数目较多,且不需要顺序排列,选用哈希构造的 unordered_set ! 最后一个测试点耗时仅需92ms。
emmm,这道题的本意应该是考察哈希表,如果语言标准库里没有的话得自己写;端正学习态度后,头铁一波……
自写哈希表,采用平方探测法/装填因子保证在0.33 。
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
struct SThash
{
int *hash;
int hmax, cnt;
};
bool isprime(int num)
{
if (num < 2)
return false;
for (int i = 2; i <= (int)sqrt(num); ++i)
if (num % i == 0)
return false;
return true;
}
int NextPrime(int num)
{
while (!isprime(num))
++num;
return num;
}
SThash *buildhash(int cnt)
{
cnt = NextPrime(cnt * 3);
SThash *T = (SThash *)malloc(sizeof(SThash));
T->hash = (int *)malloc(cnt * sizeof(int));
T->hmax = cnt;
T->cnt = 0;
memset(T->hash, -1, cnt * sizeof(int));
return T;
}
void insert(SThash *T, int value)
{
int temp{value % T->hmax}, base{0};
while (T->hash[temp] != -1)
{
if (T->hash[temp] == value)
return;
temp += ((++base) << 1) - 1;
if (temp >= T->hmax)
temp -= T->hmax;
}
T->hash[temp] = value;
++T->cnt;
return;
}
bool find(SThash *T, int value)
{
int temp{value % T->hmax}, base{0};
while (T->hash[temp] != -1 && T->hash[temp] != value)
{
temp += ((++base) << 1) - 1;
if (temp >= T->hmax)
temp -= T->hmax;
}
if (T->hash[temp] == value)
return true;
return false;
}
int getdigit(void)
{
int temp{0};
char ch;
while (1)
{
ch = getchar();
if (ch == ' ' || ch == '\n' || ch == EOF)
return temp;
temp = temp * 10 + ch - '0';
}
return -1;
}
int main(int argc, char *argv[])
{
int cnt{getdigit()};
SThash *HashTable[50];
for (int i = 0; i != cnt; ++i)
{
int ind{getdigit()};
HashTable[i] = buildhash(ind);
while (ind--)
{
int temp{getdigit()};
insert(HashTable[i], temp);
}
}
cnt = getdigit();
while (cnt--)
{
int a{getdigit()}, b{getdigit()};
--a, --b;
int sum{0};
for (int i = 0; i != HashTable[a]->hmax; ++i)
if (HashTable[a]->hash[i] != -1 && find(HashTable[b], HashTable[a]->hash[i]))
++sum;
printf("%.2lf%%\n", (sum * 1.0) / (HashTable[a]->cnt + HashTable[b]->cnt - sum) * 100.0);
}
return EXIT_SUCCESS;
}
性能和 unordered_set 差不多。
L2-006 树的遍历
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
struct node
{
int left, right;
};
node tree[35];
vector<int> a, b;
int buildtree(int left1, int right1, int left2, int right2)
{
if (left1 > right1)
return -1;
int root{a[right1]}, i;
for (i = left2; i <= right2; ++i)
if (root == b[i])
break;
int lenl{i - left2 - 1}, lenr{right2 - i - 1};
--right1;
tree[root].left = buildtree(left1, left1 + lenl, left2, i - 1);
tree[root].right = buildtree(right1 - lenr, right1, i + 1, right2);
return root;
}
void BFS(int root)
{
queue<int> Q;
Q.push(root);
printf("%d", root);
while (!Q.empty())
{
root = Q.front();
if (tree[root].left != -1)
{
Q.push(tree[root].left);
printf(" %d", tree[root].left);
}
if (tree[root].right != -1)
{
Q.push(tree[root].right);
printf(" %d", tree[root].right);
}
Q.pop();
}
putchar('\n');
return;
}
int main(int argc, char *argv[])
{
int cnt;
scanf("%d", &cnt);
for (int i = 0; i != cnt; ++i)
{
int temp;
scanf("%d", &temp);
a.push_back(temp);
}
for (int i = 0; i != cnt; ++i)
{
int temp;
scanf("%d", &temp);
b.push_back(temp);
}
BFS(buildtree(0, cnt - 1, 0, cnt - 1));
return EXIT_SUCCESS;
}
建树;写的并不熟练,需要加强这方面的练习。
L2-007 家庭房产
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
using intpair = pair<int, int>;
int unions[10000];
intpair spunions[10000];
struct ans
{
int index, number;
double Ecnt, Esum;
};
bool sortcompare(const ans &a, const ans &b)
{
if (a.Esum == b.Esum)
return a.index < b.index;
return a.Esum > b.Esum;
}
int DSUfind(const int &num)
{
if (unions[num] <= -1)
return num;
return unions[num] = DSUfind(unions[num]);
}
void DSUunion(const int &a, const int &b)
{
int spa{DSUfind(a)}, spb{DSUfind(b)};
if (spa != spb)
{
if (spa < spb)
{
unions[spa] += unions[spb];
spunions[spa].first += spunions[spb].first;
spunions[spa].second += spunions[spb].second;
unions[spb] = spa;
}
else
{
unions[spb] += unions[spa];
spunions[spb].first += spunions[spa].first;
spunions[spb].second += spunions[spa].second;
unions[spa] = spb;
}
}
}
int main(int argc, char *argv[])
{
fill(begin(unions), end(unions), -1);
int cnt;
scanf("%d", &cnt);
while (cnt--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if (b != -1)
DSUunion(a, b);
if (c != -1)
DSUunion(a, c);
int cntt;
scanf("%d", &cntt);
while (cntt--)
{
int child;
scanf("%d", &child);
DSUunion(a, child);
}
scanf("%d%d", &b, &c);
int temp{DSUfind(a)};
spunions[temp].first += b;
spunions[temp].second += c;
}
vector<ans> ANS;
for (int i = 0; i < 10000; ++i)
{
if (unions[i] < -1 || (unions[i] == -1 && spunions[i].first))
{
ans temp;
temp.index = i;
temp.number = -unions[i];
temp.Ecnt = spunions[i].first / (double)temp.number;
temp.Esum = spunions[i].second / (double)temp.number;
ANS.push_back(temp);
}
}
sort(ANS.begin(), ANS.end(), sortcompare);
printf("%llu\n", ANS.size());
for (const auto &i : ANS)
printf("%04d %d %.3lf %.3lf\n", i.index, i.number, i.Ecnt, i.Esum);
return EXIT_SUCCESS;
}
考察并查集。合并操作的同时注意合并房产套数和总面积,之后再计算平均值,按要求排序后输出。