ec9d52033f
Added comprehensive interactive demos covering: - Operating systems (2): OS overview, process/memory/filesystem - Data encoding (2): data lifecycle, encoding/storage/transmission - Network basics (5): overview, physical/data-link/transport/application layers - Data structures (5): overview, linear structures, hash table, tree, selector - Algorithms (4): overview, recursion, greedy thinking, paradigms - Programming languages (5): evolution, paradigms, scenarios, comparison, type models - Compilers (2): analogy, practice demo - Additional (5): search/sort algorithms, network principles, encoding basics, storage hierarchy, graph structures Also updated component registration in theme index.js and fixed minor formatting issues in related docs.
561 lines
12 KiB
Vue
561 lines
12 KiB
Vue
<template>
|
||
<div class="greedy-thinking-demo">
|
||
<div class="demo-header">
|
||
<span class="icon">🎯</span>
|
||
<span class="title">贪心算法:每步都选当前最优</span>
|
||
<span class="subtitle">局部最优 → 全局最优?</span>
|
||
</div>
|
||
|
||
<div class="core-idea">
|
||
<div class="idea-box">
|
||
<div class="idea-icon">💡</div>
|
||
<div class="idea-text">
|
||
贪心算法在每一步选择中都采取当前状态下<strong>最优</strong>的选择<br>
|
||
希望通过一系列局部最优选择达到<strong>全局最优</strong>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="scenario-selector">
|
||
<div class="selector-title">经典问题</div>
|
||
<div class="scenario-buttons">
|
||
<button
|
||
v-for="scenario in scenarios"
|
||
:key="scenario.id"
|
||
:class="['scenario-btn', { active: activeScenario === scenario.id }]"
|
||
@click="activeScenario = scenario.id"
|
||
>
|
||
{{ scenario.icon }} {{ scenario.name }}
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 找零钱问题 -->
|
||
<div v-if="activeScenario === 'change'" class="scenario-content">
|
||
<div class="content-title">找零钱问题</div>
|
||
<div class="change-demo">
|
||
<div class="change-amount">
|
||
需要找零:<span class="amount">{{ changeAmount }}</span> 元
|
||
</div>
|
||
<div class="change-process">
|
||
<div class="process-step" v-for="(step, index) in changeSteps" :key="index">
|
||
<div class="step-coin">{{ step.coin }}</div>
|
||
<div class="step-text">× {{ step.count }} = {{ step.value }}元</div>
|
||
</div>
|
||
</div>
|
||
<div class="change-result">
|
||
共需要 <strong>{{ totalCoins }}</strong> 个硬币
|
||
</div>
|
||
</div>
|
||
<div class="scenario-note">
|
||
✓ 贪心策略:每次选择面值最大的硬币<br>
|
||
✓ 适用于人民币、美元等货币系统
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 活动选择问题 -->
|
||
<div v-if="activeScenario === 'activity'" class="scenario-content">
|
||
<div class="content-title">活动选择问题</div>
|
||
<div class="activity-demo">
|
||
<div class="activities-list">
|
||
<div
|
||
v-for="(activity, index) in activities"
|
||
:key="index"
|
||
:class="['activity-item', { selected: activity.selected, conflicting: activity.conflicting }]"
|
||
>
|
||
<div class="activity-time">{{ activity.start }} - {{ activity.end }}</div>
|
||
<div class="activity-name">{{ activity.name }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="activity-rule">
|
||
贪心策略:<strong>选择最早结束</strong>的活动
|
||
</div>
|
||
<div class="activity-result">
|
||
最多可以参加 <strong>{{ selectedCount }}</strong> 个活动
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 最短路径 -->
|
||
<div v-if="activeScenario === 'shortest'" class="scenario-content">
|
||
<div class="content-title">最短路径问题 (Dijkstra)</div>
|
||
<div class="shortest-demo">
|
||
<div class="path-graph">
|
||
<div class="graph-nodes">
|
||
<div class="node start">A(起点)</div>
|
||
<div class="node">B</div>
|
||
<div class="node">C</div>
|
||
<div class="node">D</div>
|
||
<div class="node end">E(终点)</div>
|
||
</div>
|
||
<div class="graph-edges">
|
||
<div class="edge">A-B: 4</div>
|
||
<div class="edge">A-C: 2</div>
|
||
<div class="edge">B-D: 3</div>
|
||
<div class="edge">C-D: 1</div>
|
||
<div class="edge">C-E: 5</div>
|
||
<div class="edge">D-E: 2</div>
|
||
</div>
|
||
</div>
|
||
<div class="path-result">
|
||
<div class="result-step">从 A 出发,选择距离最近的节点</div>
|
||
<div class="result-path">A → C → D → E</div>
|
||
<div class="result-distance">总距离:2 + 1 + 2 = 5</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 贪心 vs 动态规划 -->
|
||
<div class="comparison">
|
||
<div class="comparison-title">贪心 vs 动态规划</div>
|
||
<div class="comparison-table">
|
||
<table>
|
||
<thead>
|
||
<tr>
|
||
<th>特点</th>
|
||
<th>贪心算法</th>
|
||
<th>动态规划</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td>决策方式</td>
|
||
<td>每步选当前最优</td>
|
||
<td>考虑所有可能,选最优</td>
|
||
</tr>
|
||
<tr>
|
||
<td>最优性</td>
|
||
<td>可能不是全局最优</td>
|
||
<td>保证全局最优</td>
|
||
</tr>
|
||
<tr>
|
||
<td>时间复杂度</td>
|
||
<td>O(n) 或 O(n log n)</td>
|
||
<td>O(n²) 或更高</td>
|
||
</tr>
|
||
<tr>
|
||
<td>适用场景</td>
|
||
<td>局部最优 → 全局最优</td>
|
||
<td>重叠子问题</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- 优缺点 -->
|
||
<div class="pros-cons">
|
||
<div class="pros-column">
|
||
<div class="column-title">✓ 优点</div>
|
||
<ul>
|
||
<li>实现简单</li>
|
||
<li>效率高</li>
|
||
<li>空间复杂度低</li>
|
||
</ul>
|
||
</div>
|
||
<div class="cons-column">
|
||
<div class="column-title">✗ 缺点</div>
|
||
<ul>
|
||
<li>不保证全局最优</li>
|
||
<li>适用范围有限</li>
|
||
<li>需要证明最优性</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
|
||
const activeScenario = ref('change')
|
||
|
||
const scenarios = [
|
||
{ id: 'change', name: '找零钱', icon: '💰' },
|
||
{ id: 'activity', name: '活动选择', icon: '📅' },
|
||
{ id: 'shortest', name: '最短路径', icon: '🗺️' }
|
||
]
|
||
|
||
const changeAmount = ref(37)
|
||
|
||
const changeSteps = [
|
||
{ coin: '20元', count: 1, value: 20 },
|
||
{ coin: '10元', count: 1, value: 10 },
|
||
{ coin: '5元', count: 1, value: 5 },
|
||
{ coin: '1元', count: 2, value: 2 }
|
||
]
|
||
|
||
const totalCoins = computed(() => changeSteps.reduce((sum, step) => sum + step.count, 0))
|
||
|
||
const activities = [
|
||
{ start: '9:00', end: '10:00', name: '活动1', selected: true, conflicting: false },
|
||
{ start: '9:30', end: '11:30', name: '活动2', selected: false, conflicting: true },
|
||
{ start: '10:00', end: '11:00', name: '活动3', selected: true, conflicting: false },
|
||
{ start: '10:30', end: '12:00', name: '活动4', selected: false, conflicting: true },
|
||
{ start: '11:00', end: '12:00', name: '活动5', selected: true, conflicting: false }
|
||
]
|
||
|
||
const selectedCount = computed(() => activities.filter(a => a.selected).length)
|
||
</script>
|
||
|
||
<style scoped>
|
||
.greedy-thinking-demo {
|
||
border: 1px solid var(--vp-c-divider);
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 12px;
|
||
padding: 1.5rem;
|
||
margin: 1.5rem 0;
|
||
}
|
||
|
||
.demo-header {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.demo-header .icon { font-size: 1.5rem; }
|
||
.demo-header .title { font-weight: 700; font-size: 1.1rem; }
|
||
.demo-header .subtitle { color: var(--vp-c-text-2); font-size: 0.9rem; }
|
||
|
||
.core-idea {
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.idea-box {
|
||
display: flex;
|
||
gap: 1rem;
|
||
padding: 1.25rem;
|
||
background: var(--vp-c-bg);
|
||
border-left: 4px solid var(--vp-c-brand);
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.idea-icon {
|
||
font-size: 2rem;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.idea-text {
|
||
font-size: 0.95rem;
|
||
line-height: 1.8;
|
||
}
|
||
|
||
.scenario-selector {
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.selector-title {
|
||
font-weight: 600;
|
||
font-size: 1rem;
|
||
margin-bottom: 0.75rem;
|
||
color: var(--vp-c-brand);
|
||
}
|
||
|
||
.scenario-buttons {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.scenario-btn {
|
||
padding: 0.6rem 1rem;
|
||
background: var(--vp-c-bg);
|
||
border: 2px solid var(--vp-c-divider);
|
||
border-radius: 6px;
|
||
cursor: pointer;
|
||
font-size: 0.9rem;
|
||
transition: all 0.3s;
|
||
}
|
||
|
||
.scenario-btn:hover {
|
||
border-color: var(--vp-c-brand);
|
||
}
|
||
|
||
.scenario-btn.active {
|
||
background: var(--vp-c-brand);
|
||
border-color: var(--vp-c-brand);
|
||
color: white;
|
||
}
|
||
|
||
.scenario-content {
|
||
background: var(--vp-c-bg);
|
||
border: 1px solid var(--vp-c-divider);
|
||
border-radius: 8px;
|
||
padding: 1.5rem;
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.content-title {
|
||
font-weight: 600;
|
||
font-size: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
text-align: center;
|
||
color: var(--vp-c-brand);
|
||
}
|
||
|
||
.change-demo {
|
||
text-align: center;
|
||
}
|
||
|
||
.change-amount {
|
||
font-size: 1.1rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.amount {
|
||
color: var(--vp-c-brand);
|
||
font-weight: 700;
|
||
font-size: 1.3rem;
|
||
}
|
||
|
||
.change-process {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 1rem;
|
||
margin-bottom: 1.5rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.process-step {
|
||
text-align: center;
|
||
padding: 0.75rem;
|
||
background: var(--vp-c-bg-soft);
|
||
border: 1px solid var(--vp-c-divider);
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.step-coin {
|
||
font-size: 1.2rem;
|
||
font-weight: 600;
|
||
color: var(--vp-c-brand);
|
||
margin-bottom: 0.35rem;
|
||
}
|
||
|
||
.step-text {
|
||
font-size: 0.85rem;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.change-result {
|
||
font-size: 1rem;
|
||
padding: 0.75rem;
|
||
background: rgba(16, 185, 129, 0.1);
|
||
border: 1px solid #10b981;
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.scenario-note {
|
||
margin-top: 1rem;
|
||
padding: 0.75rem;
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 6px;
|
||
font-size: 0.85rem;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
.activities-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
margin-bottom: 1.5rem;
|
||
}
|
||
|
||
.activity-item {
|
||
display: flex;
|
||
gap: 1rem;
|
||
padding: 0.75rem;
|
||
border: 1px solid var(--vp-c-divider);
|
||
border-radius: 6px;
|
||
}
|
||
|
||
.activity-item.selected {
|
||
background: rgba(16, 185, 129, 0.1);
|
||
border-color: #10b981;
|
||
}
|
||
|
||
.activity-item.conflicting {
|
||
opacity: 0.5;
|
||
}
|
||
|
||
.activity-time {
|
||
font-family: 'Courier New', monospace;
|
||
font-weight: 600;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.activity-name {
|
||
flex: 1;
|
||
}
|
||
|
||
.activity-rule {
|
||
text-align: center;
|
||
padding: 0.75rem;
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 6px;
|
||
margin-bottom: 1rem;
|
||
font-size: 0.9rem;
|
||
}
|
||
|
||
.activity-result {
|
||
text-align: center;
|
||
font-size: 1rem;
|
||
}
|
||
|
||
.shortest-demo {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 2rem;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.shortest-demo {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.path-graph {
|
||
background: var(--vp-c-bg-soft);
|
||
border-radius: 6px;
|
||
padding: 1rem;
|
||
}
|
||
|
||
.graph-nodes {
|
||
display: flex;
|
||
justify-content: space-around;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.node {
|
||
padding: 0.5rem 0.75rem;
|
||
background: var(--vp-c-bg);
|
||
border: 1px solid var(--vp-c-divider);
|
||
border-radius: 6px;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.node.start {
|
||
background: rgba(16, 185, 129, 0.1);
|
||
border-color: #10b981;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.node.end {
|
||
background: rgba(59, 130, 246, 0.1);
|
||
border-color: #3b82f6;
|
||
font-weight: 600;
|
||
}
|
||
|
||
.graph-edges {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
}
|
||
|
||
.edge {
|
||
font-size: 0.8rem;
|
||
color: var(--vp-c-text-2);
|
||
text-align: center;
|
||
}
|
||
|
||
.path-result {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0.75rem;
|
||
}
|
||
|
||
.result-step {
|
||
font-size: 0.9rem;
|
||
color: var(--vp-c-text-2);
|
||
}
|
||
|
||
.result-path {
|
||
font-size: 1.1rem;
|
||
font-weight: 600;
|
||
color: var(--vp-c-brand);
|
||
text-align: center;
|
||
}
|
||
|
||
.result-distance {
|
||
text-align: center;
|
||
font-size: 0.95rem;
|
||
}
|
||
|
||
.comparison {
|
||
margin-bottom: 2rem;
|
||
}
|
||
|
||
.comparison-title {
|
||
font-weight: 600;
|
||
font-size: 1rem;
|
||
margin-bottom: 1rem;
|
||
color: var(--vp-c-brand);
|
||
}
|
||
|
||
.comparison-table table {
|
||
width: 100%;
|
||
border-collapse: collapse;
|
||
}
|
||
|
||
.comparison-table th {
|
||
background: var(--vp-c-brand);
|
||
color: white;
|
||
padding: 0.75rem;
|
||
text-align: center;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.comparison-table td {
|
||
padding: 0.75rem;
|
||
border: 1px solid var(--vp-c-divider);
|
||
text-align: center;
|
||
font-size: 0.85rem;
|
||
}
|
||
|
||
.pros-cons {
|
||
display: grid;
|
||
grid-template-columns: 1fr 1fr;
|
||
gap: 1.5rem;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.pros-cons {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
}
|
||
|
||
.pros-column,
|
||
.cons-column {
|
||
padding: 1.25rem;
|
||
border-radius: 8px;
|
||
}
|
||
|
||
.pros-column {
|
||
background: rgba(16, 185, 129, 0.1);
|
||
border: 1px solid #10b981;
|
||
}
|
||
|
||
.cons-column {
|
||
background: rgba(239, 68, 68, 0.1);
|
||
border: 1px solid #ef4444;
|
||
}
|
||
|
||
.column-title {
|
||
font-weight: 600;
|
||
font-size: 1rem;
|
||
margin-bottom: 1rem;
|
||
}
|
||
|
||
.pros-column ul,
|
||
.cons-column ul {
|
||
margin: 0;
|
||
padding-left: 1.25rem;
|
||
}
|
||
|
||
.pros-column li,
|
||
.cons-column li {
|
||
font-size: 0.9rem;
|
||
line-height: 1.8;
|
||
}
|
||
</style>
|